Módulo 2: Estructuración y manipulación de datos con Python#

El manejo de datos es el corazón de cualquier proyecto de análisis, y Python se ha consolidado como uno de los lenguajes más poderosos y versátiles para este propósito. En este módulo, nos sumergiremos en las técnicas fundamentales para la estructuración y manipulación de datos utilizando Python, proporcionando las bases necesarias para transformar datos crudos en información útil y procesable.

Comenzaremos explorando las estructuras de datos disponibles en Python, como listas, dataframes, pilas, colas, árboles y grafos. Estas estructuras permiten organizar y acceder a la información de manera eficiente, lo que es crucial cuando se trabaja con grandes volúmenes de datos o datos complejos. Además, abordaremos cómo manipular y transformar datos no estructurados, como textos, imágenes y datos provenientes de redes sociales, que requieren enfoques y herramientas específicas para su análisis.

El módulo también se centrará en el uso de librerías especializadas como NumPy y Pandas, que son esenciales para el análisis de datos en Python. Estas librerías ofrecen potentes funciones para la manipulación y el análisis de datos estructurados, permitiendo realizar operaciones avanzadas con facilidad y eficiencia.

Además, aprenderemos a trabajar con secuencias de datos utilizando herramientas como re, string e itertools, que son fundamentales para el procesamiento y análisis de cadenas de texto y otras secuencias de información. La habilidad para manipular secuencias es clave en tareas como la limpieza de datos y la preparación de datos para modelos de machine learning.

Finalmente, exploraremos las bases de la visualización de datos para representar de manera gráfica los resultados del análisis, facilitando la interpretación y comunicación de los hallazgos. Este módulo también incluirá casos prácticos que permitirán a los participantes aplicar las técnicas aprendidas en escenarios reales, consolidando así los conceptos y habilidades adquiridos.

Archivos planos con Numpy y Pandas#

En esta sección aprenderás a importar datos a Python desde todo tipo de archivos planos, que son una forma sencilla y frecuente de almacenamiento de datos. Ya has aprendido a utilizar NumPy y Pandas: aprenderás a utilizar estos paquetes para importar archivos planos y personalizar tus importaciones.

Archivos planos#

Los archivos de texto plano se pueden clasificar en dos grandes tipos:

  1. Archivos que contienen texto sin formato . Por ejemplo:

no estructurado

  1. Archivos que contienen registros estructurados. Un ejemplo es el conjunto de datos del Titanic

estructurado

En este archivo, cada columna representa una característica o rasgo, como el género, la cabina o si la persona sobrevivió, mientras que cada fila corresponde a una persona que estaba a bordo del Titanic.

Es fundamental que cualquier científico de datos comprenda el concepto de archivo plano. Estos son archivos de texto simples que contienen datos organizados en tablas, pero sin relaciones estructuradas complejas.

Es probable que hayas notado que la extensión del archivo es .csv. Tal vez te preguntes qué significa:

  • .csv (Comma-Separated Values): Archivo en el que los valores están separados por comas.

  • .txt: Archivo de texto simple.

  • .tsv (Tab-Separated Values): Archivo en el que los valores están separados por tabulaciones.

Los valores en archivos planos pueden estar separados por diferentes caracteres, como comas o tabulaciones, conocidos como delimitadores. Estos delimitadores permiten organizar y estructurar los datos de manera sencilla y efectiva.

Ahora, para consultar cualquier archivo de texto sin formato, que debemos hacer:

  • Asignar el nombre del archivo a una variable como una cadena.

  • Usamos la función básica open de Python para abrir una conexión al archivo y le pasamos el argumento mode='r', lo que garantiza que solo podamos leerlo.

  • Despues le asignamos el texto del archivo a una variable text aplicando el método read a la conexión al archivo.

  • Después asegúrese de cerrar la conexión al archivo usando el comando file.close.

Miremos un ejemplo:

filename = '_data/datamanip/elprincipito.txt'
file = open(filename, mode='r') # 'r' es de lectura
text = file.read()
file.close()
# Imprimir el texto
print(text)
1 



En el libro se afirmaba: "La serpiente boa se traga su presa entera, sin masticarla. 
Luego ya no puede moverse y duerme durante ios seis meses que dura su 
digestión". 

Reflexioné mucho en ese momento sobre las aventuras de la jungla y a mi vez 
logré trazar con un lápiz de colores mi primer dibujo. Mi dibujo número 1 era de 
esta manera: 




Enseñé mi obra de arte a las personas mayores y les pregunté si mi dibujo les 
daba miedo. 

-¿por qué habría de asustar un sombrero? - me respondieron. 

Mi dibujo no representaba un sombrero. Representaba una serpiente boa que 
digiere un elefante. Dibujé entonces el interior de la serpiente boa a fin de que las 
personas mayores pudieran comprender. Siempre estas personas tienen 
necesidad de explicaciones. Mi dibujo número 2 era así: 

Observación

  • Para abrir un archivo en modo de escritura, debes usar mode='w'

filename = '_data/datamanip/escritura.txt'
file = open(filename, mode='w')  # 'w' es para escritura


# Escribir texto en el archivo
file.write("Era un pequeño príncipe que vivía en un planeta apenas más grande que él.")

# Cerrar el archivo después de escribir
file.close()
  • Para verificar el contenido escrito en escritura.txt, primero debes abrir el archivo en modo de escritura como se muestra arriba. Luego, abre el archivo en modo de lectura para ver el contenido:

# Abrir el archivo en modo lectura
file = open(filename, mode='r')  # 'r' es para lectura

# Leer el contenido del archivo
content = file.read()

# Imprimir el contenido
print(content)

# Cerrar el archivo después de leer
file.close()

Puedes evitar tener que cerrar la conexión al archivo utilizando una declaración with. Esto le permite crear un contexto en el que puede ejecutar comandos con el archivo abierto. Una vez fuera de esta cláusula o contexto, el archivo ya no está abierto y, por esta razón, with se denomina administrador de contexto. Realmente asegura que el archivo se cierre correctamente, incluso si ocurre un error durante la escritura. Por ejemplo:

with open('_data/datamanip/elprincipito.txt',mode ='r') as file:
    print(file.read())
1 



En el libro se afirmaba: "La serpiente boa se traga su presa entera, sin masticarla. 
Luego ya no puede moverse y duerme durante ios seis meses que dura su 
digestión". 

Reflexioné mucho en ese momento sobre las aventuras de la jungla y a mi vez 
logré trazar con un lápiz de colores mi primer dibujo. Mi dibujo número 1 era de 
esta manera: 




Enseñé mi obra de arte a las personas mayores y les pregunté si mi dibujo les 
daba miedo. 

-¿por qué habría de asustar un sombrero? - me respondieron. 

Mi dibujo no representaba un sombrero. Representaba una serpiente boa que 
digiere un elefante. Dibujé entonces el interior de la serpiente boa a fin de que las 
personas mayores pudieran comprender. Siempre estas personas tienen 
necesidad de explicaciones. Mi dibujo número 2 era así: 

Ejercicios

  1. Abre el archivo de texto GabrielGarciaMarquez.txt e imprimelo. Utiliza el administrador de contexto with.

  2. En el caso de archivos grandes, puede que no queramos imprimir todo su contenido en el shell: tal vez quieras imprimir sólo las primeras líneas. Use el archivo de texto GabrielGarciaMarquez.txt e imprima las 3 primeras líneas. Sugerencia: use el método readline().

Importación y exportación de archivos planos con Numpy#

Ahora que sabes cómo usar la función incorporada open de Python para abrir archivos de texto, veamos cómo importar un archivo plano y asignarlo a una variable. Si todos los datos son numéricos, puedes usar el paquete NumPy para importarlos como una matriz NumPy. ¿Por qué querríamos hacer esto?

Características de las matrices NumPy

  1. Eficiencia y velocidad:

    • Las matrices NumPy son el estándar de Python para almacenar datos numéricos debido a su eficiencia y rapidez.

    • Son ideales para manejar grandes volúmenes de datos de manera limpia y ordenada.

    _images/NumPy.png
  2. Compatibilidad con otros paquetes:

    • NumPy es esencial para muchos otros paquetes en Python, como scikit-learn, un popular paquete de aprendizaje automático.

    _images/scikitlearn.png
    • Al trabajar con scikit-learn, es común que los datos estén en formato de matriz NumPy.

NumPy tiene varias funciones integradas que nos permiten importar datos como matrices de forma mucho más sencilla y eficiente. Aquí se encuentran las funciones loadtxt y genfromtxt.

  1. loadtxt: Importa datos de un archivo de texto como una matriz NumPy. Por ejemplo

import numpy as np

# dataset
# mnist es una colección de dígitos manuscritos del 0 al 9

filename = '_data/datamanip/mnist.csv'
dataset = np.loadtxt(filename,delimiter=',')

dataset

Algunos argumentos adicionales de loadtxt

  • skiprows: Si deseas omitir la primera fila (por ejemplo, un encabezado), puedes usar skiprows=1.

dataset = np.loadtxt('_data/datamanip/babosa.txt', delimiter='\t', skiprows=1)
dataset
  • usecols: Si solo quieres importar columnas específicas, usa usecols con una lista de los índices de las columnas.

dataset = np.loadtxt('_data/datamanip/Startups.csv', delimiter=',',usecols=[0,1,2,4], skiprows=1)
dataset
  • dtype: Te ayuda a importar diferentes tipos de datos en matrices. dtype=str garantiza que todas las entradas se importen como cadenas

dataset = np.loadtxt('_data/datamanip/Startups.csv', delimiter=',',dtype=str)
dataset

Observación

Aunque loadtxt es útil para casos básicos. Si encuentra datos que no se pueden convertir al tipo especificado (por defecto, flotantes), generará un error, lo que puede detener el proceso de carga de datos.

  1. genfromtxt: Similar a loadtxt, pero más flexible para manejar datos mixtos. Además, cuando usamos dtype=None permite que NumPy adivine el tipo de datos para cada columna. Por ejemplo:

data = np.genfromtxt('_data/datamanip/mnist.csv', delimiter=',', dtype=None)
data

Ejercicios

Del archivo digitos.txt, que tiene la primera fila con los nombres de las variables y está delimitado por tabulaciones. Importe solo las 3 primeras columnas del archivo plano. Imprime la primera fila

Ahora, para exportar archivos planos usando NumPy, puedes utilizar la función numpy.savetxt(). Esta función es muy útil para guardar datos en un archivo de texto con un formato específico. Aquí te muestro un ejemplo básico:

# Crear una matriz NumPy
data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# Guardar la matriz en un archivo de texto
np.savetxt('_data/datamanip/archivo.txt', data, fmt='%d', delimiter=',')

Una breve explicación de los parámetros es la siguiente:

  • 'archivo.txt': Nombre del archivo en el que se guardarán los datos.

  • data: La matriz NumPy que deseas guardar.

  • fmt='%d': El formato en el que los datos se guardarán (en este caso, enteros). Puedes ajustar el formato según el tipo de datos que estás manejando (por ejemplo, %.2f para números de punto flotante con dos decimales).

  • delimiter=',': El delimitador que separa los valores en el archivo. Aquí se usa una coma, pero puedes cambiarlo a otro carácter como un espacio ' ' o un punto y coma ';'.

Si quieres agregar un encabezado al archivo, puedes hacerlo con el parámetro header:

np.savetxt('_data/datamanip/archivo.csv', data, fmt='%d', 
           delimiter=',', header='Columna1,Columna2,Columna3')

Importación y exportación de archivos planos con Pandas#

En la ciencia de datos, se requiere manejar estructuras de datos etiquetadas bidimensionales con columnas de tipos potencialmente diferentes, algo que las matrices NumPy no pueden satisfacer completamente. Esta necesidad impulsó a Wes McKinney a desarrollar la biblioteca Pandas para Python, que se ha convertido en una herramienta esencial para los científicos de datos.

Pandas es una biblioteca de Python que permite llevar a cabo todo el flujo de trabajo de análisis de datos sin cambiar a otro lenguaje específico como R. La estructura de datos más relevante en Pandas es el DataFrame, que es el análogo Pythonic del marco de datos en R.

Características claves de Pandas

  • Importación de datos: Pandas facilita la importación de archivos planos, bases de datos, archivos Excel, entre otros, como DataFrames.

  • Estructuras de datos etiquetadas: Los DataFrames permiten manipular y analizar datos con etiquetas en filas y columnas, lo que facilita el manejo de diferentes tipos de datos en un solo lugar.

  • Manipulación de datos: Pandas ofrece funciones para cortar, remodelar, agrupar, unir y fusionar datos de manera eficiente.

  • Estadísticas y manejo de valores faltantes: Realiza cálculos estadísticos sin afectar los valores faltantes y proporciona herramientas para manejar series temporales.

Ahora importemos un archivo plano con Pandas:

import pandas as pd

# Importar un archivo CSV como DataFrame
filename = '_data/datamanip/winequality-red.csv'
data = pd.read_csv(filename)

# Ver las primeras 5 filas del DataFrame
data.head()
fixed acidity;"volatile acidity";"citric acid";"residual sugar";"chlorides";"free sulfur dioxide";"total sulfur dioxide";"density";"pH";"sulphates";"alcohol";"quality"
0 7.4;0.7;0;1.9;0.076;11;34;0.9978;3.51;0.56;9.4;5
1 7.8;0.88;0;2.6;0.098;25;67;0.9968;3.2;0.68;9.8;5
2 7.8;0.76;0.04;2.3;0.092;15;54;0.997;3.26;0.65;...
3 11.2;0.28;0.56;1.9;0.075;17;60;0.998;3.16;0.58...
4 7.4;0.7;0;1.9;0.076;11;34;0.9978;3.51;0.56;9.4;5

También podemos convertir fácilmente el DataFrame en una matriz numpy.

data_array = data.to_numpy()
data_array

Observación

  1. Pandas simplifica la manipulación y análisis de datos, permitiendo realizar operaciones complejas con un código conciso y legible.

  2. Es compatible con muchas fuentes de datos, lo que lo convierte en una herramienta versátil para diferentes flujos de trabajo.

  3. Pandas tiene una comunidad activa y una documentación extensa, lo que facilita el aprendizaje y la resolución de problemas.

Para familiarizarte más con Pandas, es recomendable experimentar importando archivos planos que presenten desafíos, como comentarios incrustados y cadenas que deben interpretarse como valores faltantes. Esto te permitirá dominar las herramientas de limpieza y preparación de datos que ofrece Pandas.

Ejercicios

  1. Importe el dataset del titanic.csv, guardelo en el objeto df y muestre las 5 ultimas filas.

  2. Completa el código:

# Asignar el nombre de archivo: file
file = 'digitos.csv'

# Leer las primeras 5 filas del archivo en un DataFrame: data
# Use nrow y header
# TU CODIGO

# Construir un de numpy a partir del DataFrame: data_array
# TU CODIGO

# Imprimir el tipo de dato de data_array en la consola
print(type(data_array))
  1. Complete el código:

# Asignar el nombre del archivo: file
file = 'titanic_corrupt.txt'

# Importar el archivo: data
data = pd.read_csv(file, sep=____, comment=____, na_values=____)

# Imprimir las primeras filas del DataFrame
print(data.head())

donde

  • sep= es el delimitador que separa los campos en el archivo (en tu caso, debería ser '\t' o ',').

  • comment= especifica el carácter que indica el inicio de un comentario (en tu caso, debería ser '#' ).

  • na_values= define los valores que deben ser interpretados como valores faltantes (puedes usar `’NA’, 0 ‘NaN’ o ‘Nothing’).

Ahora, para exportar archivos planos usando pandas, puedes utilizar la función to_csv() para guardar datos en formato CSV. Aquí te muestro cómo hacerlo para archivos CSV y otros formatos comunes:

# Crear un DataFrame
data = {
    'Columna1': [1, 4, 7],
    'Columna2': [2, 5, 8],
    'Columna3': [3, 6, 9]
}
df = pd.DataFrame(data)

# Guardar el DataFrame en un archivo CSV
df.to_csv('_data/datamanip/archivo.csv', index=False)

Una breve explicación de los parámetros de to_csv():

  • 'archivo.csv': Nombre del archivo CSV a generar.

  • index=False: Evita que se guarde la columna de índices del DataFrame en el archivo CSV.

Puedes usar to_csv() con diferentes delimitadores para crear archivos de texto con otros formatos:

df.to_csv('_data/datamanip/archivo.txt', sep='\t', index=False) 

Importación e exportación de datos de otros tipos de archivos#

Como científico de datos, es crucial saber cómo importar datos desde una variedad de tipos de archivo. En esta sección, exploraremos cómo importar datos en Python desde varios formatos importantes. Cubriremos:

  • Archivos serializados (Pickle): Usados para almacenar datos de manera eficiente en Python. El concepto de serializados (Pickle) un archivo está motivado por lo siguiente: si bien puede ser fácil guardar una matriz numpy o un dataframe de pandas en un archivo plano, hay muchos otros tipos de datos, como diccionarios y listas, para los cuales no es obvio cómo almacenarlos.

  • Hojas de Cálculo Excel: Permiten integrar datos de análisis de hojas de cálculo comunes.

  • Archivos SAS y Stata: Formatoss utilizados en software de estadística y análisis de datos.

Aprenderás a manejar estos formatos para que puedas trabajar con una amplia gama de datos en tus proyectos de ciencia de datos.

Importación y exportación de datos serializados#

Los datos serializados es el proceso de convertir los datos que han sido convertidos de su formato original (por ejemplo, un diccionario, una lista, un objeto de clase, etc.) a una secuencia de bytes. Este proceso se llama serialización o marshalling. La serialización permite que estos datos se almacenen en un archivo, se envíen a través de una red o se transmitan entre diferentes partes de un programa de manera eficiente. En Python, la serialización es manejada por el módulo pickle.

Por ejemplo

import pickle

with open('_data/datamanip/data_fruta.pkl','rb') as file:
    data = pickle.load(file)
    
print(data)

Características de un archivo .pkl:

Algunas característica son:

  • Almacena una representación binaria de los objetos, lo que significa que el contenido del archivo no es legible por humanos. Solo se puede interpretar correctamente mediante deserialización utilizando pickle u otras herramientas compatibles con el formato.

  • Es ideal para guardar estructuras de datos complejas, como diccionarios, listas, o incluso objetos personalizados en Python. Estos datos pueden ser restaurados más tarde a su estado original, lo que permite la persistencia de información entre sesiones de programación.

  • Casi cualquier objeto de Python puede ser serializado a un archivo .pkl, incluyendo funciones y clases, lo que lo hace muy versátil.

Ahora, exportemos los datos a un archivo .pkl usando pickle en Python, que es útil para serializar objetos de Python (como listas, diccionarios, o DataFrames). Aquí te muestro cómo hacerlo:

# Crear un objeto (por ejemplo, un diccionario)
data = {'a': 1, 'b': 2, 'c': 3}

# Guardar el objeto en un archivo pickle
with open('_data/datamanip/archivo.pkl', 'wb') as file:
    pickle.dump(data, file)

Consideraciones

1 No cargues archivos pickle de fuentes no confiables, ya que pueden ejecutar código malicioso durante la deserialización.

  1. Archivos pickle son específicos de Python, por lo que no se pueden leer fácilmente en otros lenguajes de programación sin soporte para pickle.

Ejercicios

  1. Complete el código:

# Importar el paquete pickle 
# TU CÓDIGO

# Abre el archivo pickle y carga los datos llamados data: d
# TU CÓDIGO

# Imprime y el tipo de dato de d
# TU CÓDIGO

Importación y exportación de datos en Excel#

Las hojas de cálculo de Excel son una herramienta universalmente conocida y ampliamente utilizada, especialmente en el ámbito del análisis de datos. Un archivo de Excel generalmente contiene múltiples hojas de cálculo, cada una de las cuales puede almacenar diferentes conjuntos de datos relacionados o independientes. En el contexto de la ciencia de datos, el manejo eficiente de estos archivos es fundamental, y la biblioteca pandas de Python se destaca como una herramienta poderosa para este propósito.

Pandas permite importar archivos de Excel de manera sencilla y convertir sus hojas de cálculo en DataFrames, que son estructuras de datos optimizadas para el análisis y la manipulación de datos. La conversión de las hojas de Excel a DataFrames facilita enormemente el trabajo con los datos, ya que pandas proporciona una amplia gama de funciones para exploración, transformación y análisis.

Para comenzar, se puede utilizar la función ExcelFile de pandas para cargar un archivo de Excel en una variable, generalmente llamada data o algún nombre descriptivo. Este objeto ExcelFile actúa como un contenedor del archivo de Excel, permitiendo el acceso a sus diferentes hojas sin necesidad de cargarlas todas en la memoria al mismo tiempo.

# Especifica el nombre del archivo de Excel
file = '_data/datamanip/urbanpop.xlsx' 

# Carga el archivo de Excel en un objeto ExcelFile
data = pd.ExcelFile(file)

# Imprime la lista de nombres de las hojas en el archivo
print(data.sheet_names)

Esto indica que el archivo contiene tres hojas de cálculo, cada una correspondiente a un rango de años diferente.

Una vez que conoces los nombres de las hojas, puedes cargar cualquier hoja en particular como un DataFrame para empezar a analizar los datos. Para hacer esto, utilizas el método parse del objeto ExcelFile. Este método acepta un argumento, que puede ser el nombre de la hoja como una cadena o su índice como un número entero (no como un float, ya que Python no acepta índices de hojas en forma de floats).

# Cargar una hoja usando su nombre
df1 = data.parse('1960-1966') 

# Cargar una hoja usando su índice (comienza en 0)
df2 = data.parse(0)  

# imprimir las primeras filas
print(df1.head())

pandas es lo suficientemente inteligente para interpretar si le estás proporcionando un nombre de hoja o un índice, por lo que puedes utilizar cualquiera de los dos métodos según tu preferencia.

El método read_excel() de pandas es una función muy útil y versátil para leer archivos de Excel directamente en un DataFrame. A diferencia de ExcelFile y parse(), que se usan en conjunto cuando necesitas trabajar con múltiples hojas de un archivo de Excel, read_excel() es una función de uso directo que simplifica la lectura de una o más hojas de cálculo.

Algunos ejemplos del uso de la función read_excel()

  1. Leer una sola hoja de cálculo: Si sabes el nombre de la hoja que necesitas, puedes leerla directamente en un DataFrame:

# Lee la hoja '1960–1966' del archivo Excel y la carga en un DataFrame
df = pd.read_excel('_data/datamanip/urbanpop.xlsx', sheet_name='1960-1966')

O si prefieres usar el índice de la hoja:

# Lee la primera hoja (índice 0) del archivo Excel
df = pd.read_excel('_data/datamanip/urbanpop.xlsx', sheet_name=0)
  1. Leer múltiples hojas al mismo tiempo: Si necesitas cargar varias hojas de un archivo de Excel, read_excel() puede hacerlo en una sola llamada y devolver un diccionario donde las llaves son los nombres de las hojas y los valores son los DataFrames correspondientes.

# Lee las hojas '1960–1966' y '1975–2011' del archivo Excel
sheets = pd.read_excel('_data/datamanip/urbanpop.xlsx', sheet_name=['1960-1966', '1975-2011'])

# Accede a cada DataFrame por el nombre de la hoja
df1 = sheets['1960-1966']
df2 = sheets['1975-2011']
  1. Leer todas las hojas de un archivo de Excel: Si quieres leer todas las hojas del archivo de Excel sin tener que especificar sus nombres, puedes hacerlo pasando None al argumento sheet_name.

# Lee todas las hojas del archivo Excel
all_sheets = pd.read_excel('_data/datamanip/urbanpop.xlsx', sheet_name=None)

read_excel() es ideal para situaciones en las que necesitas una solución rápida y directa para leer archivos de Excel en Python. Su simplicidad lo hace la primera opción para la mayoría de los casos de uso, mientras que ExcelFile y parse() ofrecen más flexibilidad para tareas más complejas.

Ahora, para exportar datos a un archivo Excel usando pandas, puedes utilizar el método to_excel() del DataFrame. Aquí te muestro cómo hacerlo, con opciones para personalizar la exportación. Por ejemplo

# Crear un DataFrame
data = {
    'Columna1': [1, 4, 7],
    'Columna2': [2, 5, 8],
    'Columna3': [3, 6, 9]
}
df = pd.DataFrame(data)

# Guardar el DataFrame en un archivo Excel
df.to_excel('_data/datamanip/archivo_nuevo.xlsx', index=False)

Si quieres exportar a múltiples hojas de un archivo excel, puedes guardar diferentes DataFrames en diferentes hojas del mismo archivo Excel usando un ExcelWriter:

with pd.ExcelWriter('_data/datamanip/archivo_multihojas.xlsx') as writer:
    df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
    df2 = pd.DataFrame({'X': [5, 6], 'Y': [7, 8]})
    
    # Guardar DataFrames en hojas diferentes
    df1.to_excel(writer, sheet_name='Hoja1', index=False)
    df2.to_excel(writer, sheet_name='Hoja2', index=False)

Ejercicios

  1. Complete el código:

# Asigna el nombre del archivo de excel battledeath: file
# TU CÓDIGO

# Cargar hoja de cálculo: xls
# TU CÓDIGO

# Imprimir nombres de hojas
# TU CÓDIGO
  1. Usando el punto anterior: Complete

# Cargar una hoja en un DataFrame por nombre: df1
df1 = xls.parse(__TU CÓDIGO__)

# Imprimir las primeras filas del DataFrame df1
print(__TU CÓDIGO__)

# Cargar una hoja en un DataFrame por índice: df2
df2 = xls.parse(__TU CÓDIGO__)

# Imprimir las primeras filas del DataFrame df2
print(__TU CÓDIGO__)
  1. Usando el punto anterior. Complete en código en python. Sugerencia: Los valores pasados a skiprows y names deben ser todos del tipo list

# Analizar la primera hoja y renombrar las columnas: df1
df1 = xls.parse(__TU CÓDIGO__, skiprows=__TU CÓDIGO__, names=__TU CÓDIGO__)

# Imprimir las primeras filas del DataFrame df1
print(df1.head())

# Analizar la primera columna de la segunda hoja y renombrar la columna: df2
df2 = xls.parse(__TU CÓDIGO__, usecols=__TU CÓDIGO__, skiprows=__TU CÓDIGO__, names=__TU CÓDIGO__)

# Imprimir las primeras filas del DataFrame df2
print(df2.head())

Importación de archivos SAS y Stata usando Pandas#

Hay una amplia variedad de paquetes de software estadístico disponibles, y aunque no siempre necesites utilizarlos, como científico de datos es fundamental que puedas importar archivos de estos paquetes a tu entorno Python de manera efectiva. Esta habilidad te permitirá integrar y analizar datos de diversas fuentes, ampliando tu capacidad para realizar análisis más completos y profundos.

Importación de archivos SAS.#

SAS: Acrónimo de Statistical Analysis System (Sistema de Análisis Estadístico). Es un software popular en análisis de negocios y bioestadística. Los archivos SAS son formatos utilizados en el software SAS para realizar análisis avanzados, multivariados, inteligencia empresarial, gestión de datos, análisis predictivos y es un estándar para que los estadísticos realicen análisis computacionales. La extensión común es .sas7bdat que sirve para archivos de conjunto de datos.

Miremos un ejemplo de la importación de estos archivos:

Antes de usar el paquete sas7bdat, se debe instalar con pip install sas7bdat

 # Importa la clase SAS7BDAT del paquete sas7bdat
from sas7bdat import SAS7BDAT 

# Abre el archivo SAS usando un administrador de contexto
with SAS7BDAT('_data/datamanip/sales.sas7bdat') as file:
    df_sas = file.to_data_frame()

# imprimir
print(df_sas)

Para exportar directamente a .sas7bdat, tendrás que usar herramientas externas o software como SAS . Alternativamente, podrías buscar librerías específicas para manejar archivos SAS en lugar de intentar escribir directamente en ese formato desde pandas.

Importación de Archivos Stata.#

Stata: Un software de análisis estadístico y gestión de datos, especialmente valorado en investigación académica, incluyendo economía y epidemiología. Su área de uso es predominantemente utilizado en ciencias sociales y en investigación académica.

Los archivos Stata tienen la extensión .dta y podemos importarlos usando pandas. ¡Ni siquiera necesitamos inicializar un administrador de contexto en este caso! Simplemente pasamos el nombre del archivo a la función read_stata y lo asignamos a una variable, tal como se muestra a continuación:

# Leer el archivo Stata
df_stata = pd.read_stata('_data/datamanip/disarea.dta')
df_stata

Ahora, para exportar archivos Stata (.dta) desde Python, puedes usar la biblioteca pandas, que tiene soporte nativo para leer y escribir archivos en formato Stata.

# Crear un DataFrame de ejemplo
df = pd.DataFrame({
    'columna1': [1, 2, 3],
    'columna2': ['A', 'B', 'C']
})

# Especifica el nombre del archivo de salida
archivo_stata = '_data/datamanip/datos_exportados.dta'

# Exporta el DataFrame a un archivo Stata (.dta)
df.to_stata(archivo_stata, write_index=False)

Este método te permite exportar tus datos desde un DataFrame de pandas a un archivo Stata (.dta) de manera sencilla y efectiva.

Ejercicios

  1. Instala el paquete h5py y completa el código

# Importar paquetes de numpy y h5py
# TU CODIGO

# Asigna el nombre del archivo a la variable file y use L-L1_LOSC_4_V1-1126259446-32
# TU CODIGO

# Carga el archivo como sólo lectura en la variable data
data = h5py.File(__# TU CODIGO__, __# TU CODIGO__)

# Imprime el tipo de dato de data
# TU CODIGO

# Imprime los nombres o claves grpde los grupos en el archivo
for key in __# TU CODIGO__:
    print(__# TU CODIGO__)
  1. Instale el paquete sqlalchemy y complete el siguiente código

# Crea el engine
# Importa la función create_engine, inspect del módulo sqlalchemy
# TU CODIGO

# un motor que se conecte a la base de datos SQLite
engine = create_engine('sqlite:///_data/datamanip/Chinook.sqlite')

# Usa el Inspector para obtener los nombres de las tablas
inspector = # TU CODIGO
table_names = inspector.get_table_names()

# Imprime los nombres de las tablas
# TU CODIGO

Despues, veamos cómo hacer cada uno de estos pasos para obtener un DataFrame

from sqlalchemy import text

# Abre la conexión al engine
with engine.connect() as con:
    # Ejecutar la consulta usando text()
    rs = con.execute(text('SELECT * FROM Album'))

    # Convertir el resultado en un DataFrame de pandas
    df = pd.DataFrame(rs.fetchall())

    # Asignar los nombres de las columnas
    df.columns = rs.keys()

# Mostrar el DataFrame
print(df.head())

Conectarse a los datos de album es más facil con pandas:

# Ejecutar la consulta y almacenar los registros en un DataFrame: df
df = pd.read_sql_query('SELECT * FROM Album', engine)

# Imprimir las primeras filas del DataFrame
print(df.head())

Importación de ficheros planos desde la web#

Ahora puedes importar datos en Python desde todo tipo de archivos planos como .txt, .csv, otros tipos de archivos como archivos pickled, hojas de cálculo de Excel y archivos SAS y Stata. También has adquirido una valiosa experiencia en la consulta de bases de datos relacionales para importar datos de ellas mediante SQL. Sin embargo, todas estas habilidades implican la importación de datos de archivos que tiene localmente. Sin embargo, estas habilidades usualmente implican trabajar con archivos locales. En muchos casos, como científico de datos, necesitarás importar datos directamente desde la web.

Por ejemplo, supongamos que necesitas obtener el conjunto de datos de unas campañas de marketing directo (llamadas telefónicas) de una institución bancaria portuguesa desde el repositorio de GitHub de cdeoroaguado. Aunque puedes hacerlo manualmente usando un navegador, este método no es reproducible ni escalable. Es más eficiente y profesional utilizar código Python para automatizar la descarga e importación de estos datos.

Para hacer el proceso de importación desde la Web debemos tener algunos conceptos claros.

El paquete urllib en Python proporciona una interfaz de alto nivel para obtener datos de la World Wide Web. En particular, la función urlopen es similar a la función integrada open, pero acepta URLs en lugar de nombres de archivo.

Características de urllib

urllib tiene algunas funciones inmersas. Algunas son:

  • urlopen: Abre una URL y devuelve un objeto similar a un archivo.

  • urlretrieve: Descarga archivos directamente desde una URL y los guarda localmente.

Observación

  • Es útil para tareas sencillas de importación de datos desde la web.

  • Para tareas más complejas, podrías considerar el uso de requests junto con BeautifulSoup.

# Importar el paquete
from urllib.request import urlretrieve

# Importar pandas
import pandas as pd

# Asignar la URL del archivo: url
url ='https://raw.githubusercontent.com/cdeoroaguado/jbook_ml202430/main/data/bank/bank.csv'

# Guardar el archivo localmente
urlretrieve(url,'_data/datamanip/bank.csv')

# Leer el archivo en un DataFrame y mostrar sus primeras filas
df = pd.read_csv('_data/datamanip/bank.csv', sep=';')

# Imprimir el encabezado del dataframe
df.head()

Tambíen, podias hacer la lectura de los datos, sin descargalos. Por ejemplo

# Asignar la URL del archivo: url
url ='https://raw.githubusercontent.com/cdeoroaguado/jbook_ml202430/main/data/bank/bank.csv'

# leer el archivo en u dataframe:df
df = pd.read_csv(url,sep=';')

# Imprimir el encabezado del dataframe
df.head()

Manipulación de datos con pandas#

La librería pandas (cuyo nombre deriva de panel data, un término utilizado para describir conjuntos de datos estructurados y multidimensionales) ofrece potentes estructuras de datos y funciones de alto nivel que facilitan el trabajo con datos estructurados de manera eficiente y cómoda. Es una herramienta esencial en el análisis de datos, ampliamente utilizada por su versatilidad y funcionalidad.

_images/pandas.png

Entre los principales objetos que proporciona pandas se encuentran el DataFrame, una estructura tabular bidimensional, la Serie, ambos construidos sobre arrays multidimensionales de NumPy y el Panel, que representa un cubo de datos tridimensional. Aunque NumPy es excelente para el almacenamiento eficiente de datos con su estructura `ndarray, presenta ciertas limitaciones en análisis más complejos. Estas limitaciones incluyen la falta de flexibilidad para aplicar etiquetas a los datos, gestionar valores faltantes, realizar agrupaciones, entre otros. Pandas supera estas barreras con sus estructuras de datos avanzadas, proporcionando una mayor flexibilidad y funcionalidad.

Para más información, puedes consultar la documentación oficial de pandas, donde encontrarás recursos y ejemplos detallados para aprovechar al máximo esta poderosa librería.

Recordemos algunas cosas de pandas

Para iniciar el proceso de creación, manipulación, entre otras debemos instalar el ia en el terminal. Recuerde activar el ambiente.

installpandas

Importemos la libreria numpy y pandas

import pandas as pd
import numpy as np

Ahora, daremos los conceptos y ejemplos de una series.

Series#

Las series son estructuras similares a los arrays unidimensionales que ya hemos visto, con la diferencia de que también son homogéneas. Esto significa que todos sus elementos deben ser del mismo tipo y que su tamaño es fijo, es decir, no se puede modificar una vez definido.

Vamos a comenzar creando una serie a partir de una lista. Primero, necesitamos definir una lista con algunos datos. Por ejemplo:

# Definimos una lista de trabajos
trabajos = ["Ingeniero de Software", "Analista de Datos",
            "Diseñador UX", "Gerente de Producto",
            "Científico de datos"]

# Creamos un índice personalizado para estos trabajos
indices = ["Empresa1", "Empresa2", "Empresa3", 
           "Empresa4","Empresa5"]

Para crear la serie en Pandas usando estos datos y con indices personalizados, utilizamos el siguiente código:

# Creamos una serie con los trabajos
serie = pd.Series(data=trabajos, dtype="string")
print(serie)

# Creamos una serie con el índice personalizado
serie = pd.Series(data=trabajos, index=indices, dtype="string")
print(serie)

Ahora, vamos a crear una serie a partir de un diccionario

# Definimos un diccionario con trabajos y sus respectivos salarios
diccionario = {
    "Ingeniero de Software": 70000,
    "Analista de Datos": 60000,
    "Diseñador UX": 65000,
    "Gerente de Producto": 80000,
    "Científico de datos": 65000
}

# Creamos una serie a partir del diccionario
serie_diccionario = pd.Series(diccionario)
print(serie_diccionario)

Para explorar algunos atributos de la serie, puedes usar los siguientes métodos:

# Tamaño de nuestra serie
print(serie_diccionario.size)

# imprimir la lista de los nombres de las filas
print(serie_diccionario.index)

# imprimir el tipo de datos
print(serie_diccionario.dtype)

Para acceder a los elementos de la serie

# Accedemos a un elemento específico usando su índice
print(serie_diccionario["Ingeniero de Software"])  

# Accedemos a un rango de valores
print(serie_diccionario[0:3])  

# Accedemos a múltiples elementos usando una lista de índices
print(serie_diccionario[["Diseñador UX", "Analista de Datos"]])

También puedes utilizar algunos métodos útiles para análisis, como:

# Usamos métodos para obtener estadísticas de la serie
print(serie_diccionario.count())  # Conteo de elementos no nulos
print(serie_diccionario.sum())  # Suma de los valores
print(serie_diccionario.cumsum())  # Valores acumulados
print(serie_diccionario.value_counts())  # Conteo de valores repetidos
print(serie_diccionario.min())  # Valor mínimo
print(serie_diccionario.max())  # Valor máximo
print(serie_diccionario.mean())  # Media de los valores
print(serie_diccionario.std())  # Desviación estándar
print(serie_diccionario.quantile(0.25))  # Cuantil 1 (25%)
print(serie_diccionario.quantile(0.75))  # Cuantil 3 (75%)
print(serie_diccionario.describe())  # Resumen descriptivo de la serie

Exploraremos cómo aplicar operaciones matemáticas y funciones a series de datos relacionadas con bancos, así como buscar información mediante condiciones, ordenar series y eliminar datos nulos o desconocidos.

  1. Operaciones Matemáticas Básicas

Primero, veremos cómo aplicar operaciones matemáticas a una serie que representa los saldos de las cuentas bancarias. A continuación, presentamos algunos ejemplos prácticos:

# Una serie con saldos de cuentas bancarias

saldos = pd.Series([1500, 2000, 2500, 3000, 3500])

# Aumentar en 100 cada saldo
saldos = saldos + 100
print(saldos)

# Restar 200 a cada saldo
saldos = saldos - 200
print(saldos)

# Multiplicar cada saldo por 1.05 (aplicando un aumento del 5%)
saldos = saldos * 1.05
print(saldos)

# Dividir cada saldo por 2
saldos = saldos / 2
print(saldos)

# Comprobar si los saldos son pares o impares
print(saldos % 2)

# Aplicar la función logaritmo a cada saldo
print(saldos.apply(lambda x: np.log(x)))

Podemos aplicar funciones matemáticas a los saldos usando el método apply.Para ello debe importar el paquete math. Por ejemplo, para calcular el seno de cada saldo:

import math

# Calcular el seno de los salarios
print(saldos.apply(math.sin))
  1. Operaciones con Datos de Tipo String

Supongamos que tenemos una serie con nombres de bancos y queremos repetir cada nombre un número específico de veces:

# Crear una serie con nombres de bancos
bancos = pd.Series(['banco A', 'banco B', 'banco C'])

# Repetir cada nombre 3 veces
print(bancos.apply(lambda x: x * 3))

# Capitalizar el nombre de cada banco
print(bancos.str.title())

# Convertir todos los caracteres a minúsculas
print(bancos.str.lower())

# Convertir todos los caracteres a mayúsculas
print(print(bancos.str.upper()))

# Eliminar espacios en blanco al principio y al final
print(bancos.str.strip())

# Eliminar espacios en blanco al principio
print(bancos.str.lstrip())

# Eliminar espacios en blanco al final
print(bancos.str.rstrip())

# Reemplazar 'Banco' por 'Entidad'
print(bancos.str.replace('banco', 'entidad'))

# Dividir cadenas en una lista de substrings por un delimitador
print(bancos.str.split(' '))

# Unir las cadenas en una sola con un delimitador
print(bancos.str.join(', '))

# Encontrar la posición de 'Banco' en cada cadena
print(bancos.str.find('banco'))

# Verificar si cada cadena contiene 'A'
print(bancos.str.contains('A'))

# Extraer los primeros 4 caracteres de cada cadena
print(bancos.str[:4])

# Contar el número de veces que aparece 'Banco'
print(bancos.str.count('banco'))

# Verificar si cada cadena comienza con 'banco'
bancos.str.startswith('banco')

# Verificar si cada cadena termina con 'A'
bancos.str.endswith('A')

# Reemplazar dígitos por 'X'
bancos.str.replace(r'\d+', 'X', regex=True)

# Obtener la longitud de cada cadena
bancos.str.len()

# Eliminar caracteres no alfabéticos
bancos.str.replace(r'[^a-zA-Z\s]', '', regex=True)
  1. Filtrado de Datos

El objetivo es seleccionar saldos que cumplan una condición. Por ejemplo

# Seleccionar saldos mayores o iguales a 3000
print(saldos[saldos >= 3000])

# Seleccionar saldos diferentes a 3000
print(saldos[saldos != 3000])
  1. Ordenar series

Para ordenar los saldos de manera ascendente o descendente:

# Ordenar los saldos de manera ascendente
print(saldos.sort_values(ascending=True))

# Ordenar los saldos de manera descendente
print(saldos.sort_values(ascending=False))

# Ordenar por índices de manera ascendente
print(saldos.sort_index(ascending=True))

# Ordenar por índices de manera descendente
print(saldos.sort_index(ascending=False))
  1. Eliminación de Datos Nulos y Desconocidos

Finalmente, para eliminar datos nulos o desconocidos en la serie de saldos:

# Crear valores nulos en la serie de saldos
saldos = pd.Series([1500, np.nan, 2500, None, 3500])

# Eliminar valores nulos
saldos_limpios = saldos.dropna()
print(saldos_limpios)

Con estos ejemplos, has aprendido cómo realizar diversas operaciones con series relacionadas con datos bancarios en Pandas. En la próximo sección, exploraremos cómo trabajar con DataFrames.

Pandas#

En este módulo, profundizaremos en la creación de DataFrames, una de las estructuras de datos más versátiles y poderosas para la manipulación de información financiera. Exploraremos tres métodos distintos para construir DataFrames, cada uno con aplicaciones específicas en la industria bancaria.

Un DataFrame es una estructura bidimensional, similar a una tabla, que nos permite organizar y manipular datos con facilidad. En el contexto bancario, los DataFrames son ideales para manejar información de clientes, transacciones, productos financieros, y otros tipos de datos críticos.

Método 1: Creación de DataFrames a partir de Diccionarios#

En este primer enfoque, utilizaremos un diccionario para organizar los datos de clientes bancarios. Las claves del diccionario representarán las columnas del DataFrame, tales como Nombre, Edad, Saldo, y Calificación_Crédito.

# Importación de la librería pandas
import pandas as pd

# Definición de los datos mediante un diccionario
clientes = {
    'Nombre': ['José', 'Rodolfo', 'María', 'Julieta'],
    'Edad': [45, 52, 34, 29],
    'Saldo': [50000, 70000, 60000, 15000],
    'Calificación_Crédito': [700, 750, 680, 720]
}

# Creación del DataFrame utilizando el diccionario
df_clientes = pd.DataFrame(clientes)

# Visualización del DataFrame
print(df_clientes)

Este enfoque es eficiente cuando se tiene un conjunto de datos bien estructurado, con columnas predefinidas y valores coherentes. Es comúnmente utilizado en situaciones donde los datos provienen de sistemas bancarios estructurados, como bases de datos relacionales.

Método 2: Creación de DataFrames a partir de Listas Anidadas#

El siguiente método consiste en utilizar listas de listas para estructurar los datos. Este enfoque puede ser útil cuando los datos provienen de una fuente menos estructurada, como archivos CSV o entrada manual.

# Definición de los datos mediante listas anidadas
datos_clientes = [
    ['José', 45, 50000, 700],
    ['Rodolfo', 52, 70000, 750],
    ['María', 34, 60000, 680],
    ['Julieta', 29, 15000, 720]
]

# Definición de las columnas
columnas = ['Nombre', 'Edad', 'Saldo', 'Calificación_Crédito']

# Creación del DataFrame
df_clientes_lista = pd.DataFrame(datos_clientes, columns=columnas)

# Visualización del DataFrame
print(df_clientes_lista)

Este método es particularmente útil cuando los datos no están previamente etiquetados y requieren un procesamiento adicional para ser organizados en un formato tabular. Es frecuente en la integración de datos desde múltiples fuentes no homogéneas, como encuestas o registros de transacciones.

Método 3: Creación de DataFrames a partir de Listas de Diccionarios#

Finalmente, exploraremos cómo crear un DataFrame a partir de una lista de diccionarios. Este método es flexible y permite manejar datos con campos opcionales o información incompleta, algo común en grandes bases de datos bancarias.

# Definición de los datos mediante una lista de diccionarios
clientes_dict = [
    {'Nombre': 'José', 'Edad': 45, 'Saldo': 50000, 'Calificación_Crédito': 700},
    {'Nombre': 'Rodolfo', 'Edad': 52, 'Saldo': 70000, 'Calificación_Crédito': 750},
    {'Nombre': 'María', 'Edad': 34, 'Saldo': 60000},  # Falta calificación de crédito
    {'Nombre': 'Julieta', 'Edad': 29, 'Calificación_Crédito': 720},  # Falta saldo
    {'Edad': 28, 'Saldo': 30000}  # Faltan nombre y calificación de crédito
]

# Creación del DataFrame
df_clientes_dict = pd.DataFrame(clientes_dict)

# Visualización del DataFrame
print(df_clientes_dict)

La capacidad de manejar datos incompletos o parcialmente definidos es crucial en el análisis de datos bancarios, donde la información puede provenir de fuentes dispares y no siempre estará completa. Este método permite construir DataFrames robustos que pueden ser limpiados o completados en etapas posteriores del análisis.

Observación

Algunas diferencias clave entre una Serie (Series) y un DataFrame en Pandas:

  1. Dimensionalidad:

    • Serie: Es unidimensional, como una lista o columna única de datos.

    • DataFrame: Es bidimensional, similar a una tabla con múltiples filas y columnas.

  2. Estructura:

    • Serie: Contiene una sola columna de datos con un índice.

    • DataFrame: Contiene múltiples columnas, cada una de las cuales es una Serie.

  3. Uso:

    • Serie: Ideal para manejar una sola secuencia de datos.

    • DataFrame: Ideal para trabajar con datos tabulares que tienen múltiples variables o características.

  4. Etiquetas del Eje:

    • Serie: Tiene un único conjunto de etiquetas o índice asociado con los datos.

    • DataFrame: Tiene dos ejes de etiquetas: uno para las filas (índice) y otro para las columnas.

  5. Operaciones de Agregación:

    • Serie: Las operaciones de agregación, como la suma o el promedio, se aplican directamente a la secuencia de datos.

    • DataFrame: Puedes aplicar operaciones de agregación a lo largo de filas o columnas, permitiendo un análisis más detallado y comparativo.

Manipulación#

La manipulación de datos con Pandas es una de las habilidades fundamentales en el análisis de datos. Pandas es una biblioteca de Python que proporciona estructuras de datos fáciles de usar, como Series y DataFrames, que permiten realizar operaciones y transformaciones complejas de manera sencilla y eficiente.

Introducción a la manipulación de datos#

Ahora carguemos el conjunto de datos de marketing del banco bank-full.

Los datos están relacionados con campañas de marketing directo (llamadas telefónicas) de una institución bancaria portuguesa.

Este conjunto de datos tiene 4521 observaciones y 17 variables. Las variables son:

  • age: Edad del cliente.

  • job: Profesión del cliente (por ejemplo, desempleado, servicios, gestión).

  • marital: Estado civil del cliente (soltero, casado, divorciado).

  • education: Nivel educativo del cliente (primaria, secundaria, terciaria).

  • default : Indica si el cliente tiene crédito en incumplimiento (sí o no).

  • balance: Saldo promedio anual de la cuenta bancaria del cliente.

  • housing: Indica si el cliente tiene un préstamo hipotecario (sí o no).

  • loan: Indica si el cliente tiene un préstamo personal (sí o no).

  • contact: Tipo de comunicación de contacto (teléfono celular, teléfono fijo).

  • day: Día del mes en que se realizó el último contacto con el cliente.

  • month: Mes en que se realizó el último contacto con el cliente.

  • duration: Duración del último contacto en segundos.

  • campaign: Número de contactos realizados durante esta campaña de marketing.

  • pdays: Días que han pasado desde que el cliente fue contactado por última vez en una campaña anterior (valores -1 indican que el cliente no fue contactado previamente).

  • previous: Número de contactos realizados antes de esta campaña.

  • poutcome: Resultado de una campaña de marketing anterior (éxito, fracaso, desconocido).

  • y: Resultado de la campaña actual (si el cliente suscribió o no un depósito a plazo fijo).

# importar librerias
import pandas as pd
import numpy as np

# Asignar la URL del archivo: url
url ='https://raw.githubusercontent.com/cdeoroaguado/Datos/refs/heads/main/datamanip/bank/bank-full.csv'

# leer el archivo en u dataframe:df
df = pd.read_csv(url,sep=';')

# Imprimir el encabezado del dataframe
df.head()

# Mostrar las 5 ultimas filas de DataFrame
df.tail()

# Concatenar el encabezado y las últimas 5 filas del DataFrame
result = pd.concat([df.head(), df.tail()])
print(result)

# Para ignorar el indice
print(pd.concat([df.head(), df.tail()],ignore_index=True))
       age           job   marital  education default  balance housing loan  \
0       58    management   married   tertiary      no     2143     yes   no   
1       44    technician    single  secondary      no       29     yes   no   
2       33  entrepreneur   married  secondary      no        2     yes  yes   
3       47   blue-collar   married    unknown      no     1506     yes   no   
4       33       unknown    single    unknown      no        1      no   no   
45206   51    technician   married   tertiary      no      825      no   no   
45207   71       retired  divorced    primary      no     1729      no   no   
45208   72       retired   married  secondary      no     5715      no   no   
45209   57   blue-collar   married  secondary      no      668      no   no   
45210   37  entrepreneur   married  secondary      no     2971      no   no   

         contact  day month  duration  campaign  pdays  previous poutcome    y  
0        unknown    5   may       261         1     -1         0  unknown   no  
1        unknown    5   may       151         1     -1         0  unknown   no  
2        unknown    5   may        76         1     -1         0  unknown   no  
3        unknown    5   may        92         1     -1         0  unknown   no  
4        unknown    5   may       198         1     -1         0  unknown   no  
45206   cellular   17   nov       977         3     -1         0  unknown  yes  
45207   cellular   17   nov       456         2     -1         0  unknown  yes  
45208   cellular   17   nov      1127         5    184         3  success  yes  
45209  telephone   17   nov       508         4     -1         0  unknown   no  
45210   cellular   17   nov       361         2    188        11    other   no  
   age           job   marital  education default  balance housing loan  \
0   58    management   married   tertiary      no     2143     yes   no   
1   44    technician    single  secondary      no       29     yes   no   
2   33  entrepreneur   married  secondary      no        2     yes  yes   
3   47   blue-collar   married    unknown      no     1506     yes   no   
4   33       unknown    single    unknown      no        1      no   no   
5   51    technician   married   tertiary      no      825      no   no   
6   71       retired  divorced    primary      no     1729      no   no   
7   72       retired   married  secondary      no     5715      no   no   
8   57   blue-collar   married  secondary      no      668      no   no   
9   37  entrepreneur   married  secondary      no     2971      no   no   

     contact  day month  duration  campaign  pdays  previous poutcome    y  
0    unknown    5   may       261         1     -1         0  unknown   no  
1    unknown    5   may       151         1     -1         0  unknown   no  
2    unknown    5   may        76         1     -1         0  unknown   no  
3    unknown    5   may        92         1     -1         0  unknown   no  
4    unknown    5   may       198         1     -1         0  unknown   no  
5   cellular   17   nov       977         3     -1         0  unknown  yes  
6   cellular   17   nov       456         2     -1         0  unknown  yes  
7   cellular   17   nov      1127         5    184         3  success  yes  
8  telephone   17   nov       508         4     -1         0  unknown   no  
9   cellular   17   nov       361         2    188        11    other   no  

Las dimensiones del dataset:

# Obtener las dimensiones del DataFrame
df.shape
(45211, 17)

Información de la estructura del dataset de marketing:

# Obtener información sobre la estructura del DataFrame
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 45211 entries, 0 to 45210
Data columns (total 17 columns):
 #   Column     Non-Null Count  Dtype 
---  ------     --------------  ----- 
 0   age        45211 non-null  int64 
 1   job        45211 non-null  object
 2   marital    45211 non-null  object
 3   education  45211 non-null  object
 4   default    45211 non-null  object
 5   balance    45211 non-null  int64 
 6   housing    45211 non-null  object
 7   loan       45211 non-null  object
 8   contact    45211 non-null  object
 9   day        45211 non-null  int64 
 10  month      45211 non-null  object
 11  duration   45211 non-null  int64 
 12  campaign   45211 non-null  int64 
 13  pdays      45211 non-null  int64 
 14  previous   45211 non-null  int64 
 15  poutcome   45211 non-null  object
 16  y          45211 non-null  object
dtypes: int64(7), object(10)
memory usage: 5.9+ MB

El atributo df.size en pandas devuelve el número total de elementos en un DataFrame. Esto se calcula multiplicando el número de filas por el número de columnas. Es útil para obtener una visión rápida del tamaño total del DataFrame en términos de elementos.

# número total de elementos en el dataframe
df.size
768587

Puede ocurrir que el conjunto de datos de marketing para la banca tenga duplicados. El método drop_duplicates() en pandas se utiliza para eliminar filas duplicadas de un DataFrame. Este método permite identificar y remover filas que contienen los mismos valores en las columnas seleccionadas, o en todas las columnas si no se especifica ninguna.

# Eliminar filas duplicadas
df = df.drop_duplicates()
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 45211 entries, 0 to 45210
Data columns (total 17 columns):
 #   Column     Non-Null Count  Dtype 
---  ------     --------------  ----- 
 0   age        45211 non-null  int64 
 1   job        45211 non-null  object
 2   marital    45211 non-null  object
 3   education  45211 non-null  object
 4   default    45211 non-null  object
 5   balance    45211 non-null  int64 
 6   housing    45211 non-null  object
 7   loan       45211 non-null  object
 8   contact    45211 non-null  object
 9   day        45211 non-null  int64 
 10  month      45211 non-null  object
 11  duration   45211 non-null  int64 
 12  campaign   45211 non-null  int64 
 13  pdays      45211 non-null  int64 
 14  previous   45211 non-null  int64 
 15  poutcome   45211 non-null  object
 16  y          45211 non-null  object
dtypes: int64(7), object(10)
memory usage: 5.9+ MB

Observación

Si nuestro conjunto de datos de marketing en la banca contiene valores nulos, se utiliza el método dropna() o. Este método te permite eliminar filas o columnas que contengan valores nulos (NaN). A continuación te muestro cómo hacerlo:


# Eliminar todas las filas que contengan al menos un valor nulo
df_sin_nulos = df.dropna()

# Eliminar filas que contengan al menos un valor nulo
df_sin_nulos_filas = df.dropna(axis=0)

# Eliminar columnas que contengan al menos un valor nulo
df_sin_nulos_columnas = df.dropna(axis=1)

# Mostrar los DataFrames sin valores nulos
print("DataFrame sin valores nulos en filas:")
print(df_sin_nulos_filas)

print("\nDataFrame sin valores nulos en columnas:")
print(df_sin_nulos_columnas)

Consideraciones

El uso de df.dropna() puede resultar en la pérdida de datos importantes si una gran cantidad de valores nulos está presente. Antes de eliminar los valores nulos, considera las siguientes opciones:

  • Imputar Valores Nulos: Puedes reemplazar los valores nulos con valores específicos utilizando df.fillna().

  • Revisar el Impacto: Evalúa cómo la eliminación de valores nulos afectará tu análisis y si es necesario ajustar tu enfoque para manejar los datos faltantes de manera más adecuada.

Ahora, el nombres de las variables, el indice, el tipo de dato del dataset de marketing

# nombre de las variables
print(df.columns)

# Obtener el índice del DataFrame
print(df.index)

# tipo de dato
print(df.dtypes)
Index(['age', 'job', 'marital', 'education', 'default', 'balance', 'housing',
       'loan', 'contact', 'day', 'month', 'duration', 'campaign', 'pdays',
       'previous', 'poutcome', 'y'],
      dtype='object')
RangeIndex(start=0, stop=45211, step=1)
age           int64
job          object
marital      object
education    object
default      object
balance       int64
housing      object
loan         object
contact      object
day           int64
month        object
duration      int64
campaign      int64
pdays         int64
previous      int64
poutcome     object
y            object
dtype: object

Observación

  1. Si quieres cambiar el nombre de las columnas o los indices. Usas df.rename de la siguiente forma

df.rename(columns={},index={})
  1. Para reindexar un dataframe debemos usardf.reindex y los selecciona:

df.reindex(index = [],columns = [],fill_value='')

Queremos saber los clientes menores de 20 años:

# Seleccionar solo las filas donde la condición es True
df.loc[:,'age'] < 20

# Mostrar los clientes menores de 20 años
dfm20 = df[df.loc[:,'age'] < 20]

# imprimir el dataframe las 5 primeras
dfm20.head()
age job marital education default balance housing loan contact day month duration campaign pdays previous poutcome y
30791 19 student single unknown no 1169 no no cellular 6 feb 463 18 -1 0 unknown no
31041 19 student single unknown no 0 no no cellular 11 feb 123 3 -1 0 unknown no
31263 19 student single unknown no 27 no no telephone 5 mar 86 12 -1 0 unknown no
31304 19 student single secondary no 1803 no no cellular 10 mar 59 1 -1 0 unknown no
31432 19 student single primary no 134 no no cellular 27 mar 271 2 -1 0 unknown yes

Escojamos las columnas age, marital, balance, y de los clientes menores de 20

# seleccionemos las columnas
new_dfm20 = dfm20[['age','marital','balance','y']]

# imprimir
print(new_dfm20.head())
       age marital  balance    y
30791   19  single     1169   no
31041   19  single        0   no
31263   19  single       27   no
31304   19  single     1803   no
31432   19  single      134  yes

Observación

Otra forma de seleccionar las columnas es la siguiente:

new_df = pd.read_csv(url,sep=';',usecols=['age','marital','balance','y'])

Para agregar y eliminar columnas o filas:

  1. Puedes agregar una columna a un DataFrame en pandas usando una Serie (Series) de la siguiente manera:

# Crear una Serie con los datos que quieres agregar como nueva columna
nueva_columna = pd.Series([valor1, valor2, valor3, ...], index=df.index)

# Agregar la Serie al DataFrame como una nueva columna
df['nombre_nueva_columna'] = nueva_columna

# Mostrar el DataFrame con la nueva columna
print(df)
  1. Para eliminar una, dos o más columnas de un DataFrame en pandas, puedes pasar una lista con los nombres de las columnas al método drop(). A continuación te muestro cómo hacerlo:

# Crear una lista con los nombres de las columnas que quieres eliminar
columnas_a_eliminar = ['nombre_columna1', 'nombre_columna2']

# Eliminar las columnas especificadas en la lista
df.drop(columnas_a_eliminar, axis=1, inplace=True)

# Mostrar el DataFrame actualizado
print(df)
  1. Para agregar una nueva fila a un DataFrame en pandas, puedes seguir estos pasos generales:

# Crear una nueva fila como un diccionario
nueva_fila = {
    'columna1': valor1,
    'columna2': valor2,
    'columna3': valor3,
    # Agregar más columnas si es necesario
}

# Convertir la nueva fila en un DataFrame
nueva_fila_df = pd.DataFrame([nueva_fila])

# Agregar la nueva fila al DataFrame original
df = df.append(nueva_fila_df, ignore_index=True)

# Mostrar el DataFrame actualizado
print(df)
  1. Para eliminar una fila de un DataFrame en pandas, puedes seguir estos pasos generales:

# Identificar el índice de la fila que deseas eliminar
indice_a_eliminar = 5 

# Usar el método drop() para eliminar la fila
df = df.drop(indice_a_eliminar, axis=0)

# (Opcional) Resetear los índices si es necesario
df = df.reset_index(drop=True)

# Mostrar el DataFrame actualizado
print(df)

Para saber quien tiene mayor balance en la cuenta de los menores de 20, debo ordenarlo usando el método sort_values:

# ordenar
new_dfm20.sort_values(by='balance',ascending=False)
age marital balance y
34281 19 single 5368 no
40736 18 single 1944 no
40376 19 single 1803 no
31304 19 single 1803 no
33774 19 single 1247 no
30791 19 single 1169 no
31492 19 single 779 yes
32169 19 single 626 no
43680 19 single 608 yes
42274 18 single 608 yes
40887 18 single 608 yes
41446 19 single 527 no
42488 19 single 526 no
44058 19 single 526 no
44644 18 single 438 no
44042 19 single 424 no
43408 19 single 394 yes
44110 19 single 372 yes
43637 18 single 348 yes
41930 19 single 329 yes
43594 19 single 329 yes
44211 19 single 302 yes
34675 19 single 291 no
45170 19 single 245 no
41619 19 single 179 no
42146 18 single 156 no
31432 19 single 134 yes
44493 19 single 108 yes
40744 18 single 108 yes
41487 18 single 108 yes
42954 18 single 108 yes
43258 19 single 108 yes
42705 19 single 103 no
40564 19 single 103 yes
41830 19 single 103 no
33789 19 single 96 no
41500 19 single 88 no
41057 19 single 60 no
40927 19 single 56 no
41706 19 single 55 no
41222 18 single 35 no
31263 19 single 27 no
41252 18 single 5 no
41402 19 single 4 no
41273 18 single 3 yes
34288 19 single 0 no
31041 19 single 0 no

Puedes aplicar una función personalizada a una columna específica del DataFrame usando el método apply() de pandas. Supongamos que deseas crear una nueva columna llamada balance_category que clasifique el balance de cada cliente en "Bajo", "Medio" o "Alto" según ciertos umbrales.

# Definir una función para categorizar el balance
def categorizar_balance(balance):
    if balance < 500:
        return 'Bajo'
    elif 500 <= balance < 1500:
        return 'Medio'
    else:
        return 'Alto'
# Aplicar la función 'categorizar_balance' a la columna 'balance'
# y crear la nueva columna 'balance_category'
new_dfm20.loc[:,'balance_category'] = new_dfm20['balance'].apply(categorizar_balance)

# Mostrar el DataFrame actualizado
print(new_dfm20.head())
       age marital  balance    y balance_category
30791   19  single     1169   no            Medio
31041   19  single        0   no             Bajo
31263   19  single       27   no             Bajo
31304   19  single     1803   no             Alto
31432   19  single      134  yes             Bajo

Observación

Podemos aplicar funciones que ya tienen implementadas python o podemos usar la función lambda

  1. Con una función que tiene implementada python

import math

new_dfm20['rounded_balance'] = new_dfm20['balance'].apply(math.ceil)
  1. Con la función lambda

new_dfm20['rounded_balance_to_100'] = new_dfm20['balance'].apply(lambda x: 100*math.ceil(x))

Ahora, debemos obtener los clientes menores de 20 que si se suscribieron. Ademas los que se suscribieron con balance bajo.

# menores de 20 que se suscribieron
new_dfm20[new_dfm20['y']=='yes']

# Otra forma de seleccionarlos
new_dfm20[new_dfm20["y"].isin(["yes"])]

# menores de 20 que se suscribieron con balance bajo
new_dfm20[(new_dfm20['y']=='yes') & (new_dfm20['balance_category']=='Bajo')].head()
age marital balance y balance_category
31432 19 single 134 yes Bajo
40564 19 single 103 yes Bajo
40744 18 single 108 yes Bajo
41273 18 single 3 yes Bajo
41487 18 single 108 yes Bajo
Adición de nuevas columnas al DataFrame#

En este ejercicio, vamos a añadir nuevas columnas al conjunto de datos de diamantes en la biblioteca pandas. Empezaremos con la adición simple de columnas y luego avanzaremos y veremos la adición condicional de columnas. Para ello, vamos a seguir los siguientes pasos:

  • Anade una columna balance_por_age al DataFrame. Del mismo modo, también podemos utilizar la suma, la resta y otros operadores matemáticos sobre dos columnas numéricas.

new_dfm20.loc[:,'balance_por_age'] = new_dfm20['balance']/new_dfm20['age']
print(new_dfm20.head())
       age marital  balance    y balance_category  balance_por_age
30791   19  single     1169   no            Medio        61.526316
31041   19  single        0   no             Bajo         0.000000
31263   19  single       27   no             Bajo         1.421053
31304   19  single     1803   no             Alto        94.894737
31432   19  single      134  yes             Bajo         7.052632
  • Ahora, veremos la adición condicional de columnas. Vamos a intentar añadir una columna basada en el valor de la edad, digamos que todo lo que sea más de 17 como mayor de edad (codificado como 1) y todo lo que sea inferior a 17 como menor de edad (codificado como 0).

new_dfm20.loc[:,'age_cat'] = np.where(new_dfm20['age'] > 17, 1, 0)
print(new_dfm20.tail())
       age marital  balance    y balance_category  balance_por_age  age_cat
44110   19  single      372  yes             Bajo        19.578947        1
44211   19  single      302  yes             Bajo        15.894737        1
44493   19  single      108  yes             Bajo         5.684211        1
44644   18  single      438   no             Bajo        24.333333        1
45170   19  single      245   no             Bajo        12.894737        1

Descripción estadística#

Exploraremos cómo obtener estadísticas de resumen detalladas para columnas específicas de un DataFrame, así como cómo realizar análisis estadísticos avanzados mediante agrupaciones y tablas dinámicas. Comenzaremos con el cálculo de métricas descriptivas básicas, tales como medias, medianas, y desviaciones estándar, para evaluar la distribución y variabilidad de los datos. A continuación, abordaremos técnicas para aplicar estas estadísticas a subconjuntos de datos mediante agrupaciones, permitiendo un análisis más granular y enfocado.

Finalmente, dominaremos el uso de tablas dinámicas para sintetizar, visualizar y resumir datos complejos, facilitando la extracción de insights clave y patrones significativos en grandes volúmenes de información. Este enfoque integral fortalecerá tu capacidad para extraer, interpretar y comunicar hallazgos estadísticos de manera efectiva en el análisis de datos.

Resumen estadístico univariado#

Calculemos las medidas descriptivas fundamentales, incluyendo la media, mediana, moda, varianza, desviación estándar y cuartiles, para proporcionar una visión general de la distribución de los datos. Usaremos el conjunto de datos.

  1. Si la variable es numérica

# Descriptivo de una sola variable numérica solo promedio
print(df['age'].mean())

# Resumen descriptivo de una sola variable numérica
print(df['age'].agg({
    'Promedio': 'mean',                       # Media
    'Desviacion_Estandar': 'std',             # Desv Estandar
    'Minimo': 'min',                          # Mínimo
    'Maximo': 'max',                          # Máximo
    'Mediana': 'median',                      # Mediana usando 'median' en lugar de np.median
    'Cuantil 1': lambda x: x.quantile(0.25),  # Cuantil 25%
    'Cuantil 3': lambda x: x.quantile(0.75)   # Cuantil 75%
}))
40.93621021432837
Promedio               40.936210
Desviacion_Estandar    10.618762
Minimo                 18.000000
Maximo                 95.000000
Mediana                39.000000
Cuantil 1              33.000000
Cuantil 3              48.000000
Name: age, dtype: float64
# Descriptivo de una varias variable numérica solo promedio
print(df[['age','balance']].mean())
              
# Resumen descriptivo de varias variable numérica
result = pd.DataFrame({
    'Promedio': df[['age', 'balance']].mean(),
    'Desv. Estandar': df[['age', 'balance']].std(),
    'minimo': df[['age', 'balance']].min(),
    'maximo': df[['age', 'balance']].max(),
    'mediana': df[['age', 'balance']].median(),
    'Cuantil 1': df[['age', 'balance']].quantile(0.25),
    'Cuantil 3': df[['age', 'balance']].quantile(0.75)
})

# Mostrar los resultados
print(result.T)
age          40.936210
balance    1362.272058
dtype: float64
                      age        balance
Promedio        40.936210    1362.272058
Desv. Estandar  10.618762    3044.765829
minimo          18.000000   -8019.000000
maximo          95.000000  102127.000000
mediana         39.000000     448.000000
Cuantil 1       33.000000      72.000000
Cuantil 3       48.000000    1428.000000
  1. Si la variable es catégorica

# Descriptivo de una sola variable categórica solo conteo
conteo = df['job'].value_counts()
print(conteo)

# Descriptivo de una sola variable categórica solo proporcion
proporciones = df['job'].value_counts(normalize=True)
print(proporciones)

# Combinar los resultados en un solo DataFrame
resultado = pd.DataFrame({
    'Conteo': conteo,
    'Proporción': proporciones
})

# imprimir
print(resultado)
job
blue-collar      9732
management       9458
technician       7597
admin.           5171
services         4154
retired          2264
self-employed    1579
entrepreneur     1487
unemployed       1303
housemaid        1240
student           938
unknown           288
Name: count, dtype: int64
job
blue-collar      0.215257
management       0.209197
technician       0.168034
admin.           0.114375
services         0.091880
retired          0.050076
self-employed    0.034925
entrepreneur     0.032890
unemployed       0.028820
housemaid        0.027427
student          0.020747
unknown          0.006370
Name: proportion, dtype: float64
               Conteo  Proporción
job                              
blue-collar      9732    0.215257
management       9458    0.209197
technician       7597    0.168034
admin.           5171    0.114375
services         4154    0.091880
retired          2264    0.050076
self-employed    1579    0.034925
entrepreneur     1487    0.032890
unemployed       1303    0.028820
housemaid        1240    0.027427
student           938    0.020747
unknown           288    0.006370
# Descriptivo de varias variable categórica solo conteo
conteo = df[['job','education']].value_counts()
# print(conteo)

# Descriptivo de varias variable categórica solo proporcion
proporciones = df[['job','education']].value_counts(normalize=True)
# print(proporciones)

# Combinar los resultados en un solo DataFrame
resultado = pd.DataFrame({
    'Conteo': conteo,
    'Proporción': proporciones
})

# imprimir
print(resultado)
                         Conteo  Proporción
job           education                    
management    tertiary     7801    0.172547
blue-collar   secondary    5371    0.118799
technician    secondary    5229    0.115658
admin.        secondary    4219    0.093318
blue-collar   primary      3758    0.083121
services      secondary    3457    0.076464
technician    tertiary     1968    0.043529
management    secondary    1121    0.024795
retired       secondary     984    0.021765
self-employed tertiary      833    0.018425
retired       primary       795    0.017584
unemployed    secondary     728    0.016102
entrepreneur  tertiary      686    0.015173
housemaid     primary       627    0.013868
self-employed secondary     577    0.012762
admin.        tertiary      572    0.012652
entrepreneur  secondary     542    0.011988
student       secondary     508    0.011236
blue-collar   unknown       454    0.010042
housemaid     secondary     395    0.008737
retired       tertiary      366    0.008095
services      primary       345    0.007631
management    primary       294    0.006503
unemployed    tertiary      289    0.006392
              primary       257    0.005684
management    unknown       242    0.005353
technician    unknown       242    0.005353
student       tertiary      223    0.004932
admin.        primary       209    0.004623
services      tertiary      202    0.004468
entrepreneur  primary       183    0.004048
housemaid     tertiary      173    0.003827
admin.        unknown       171    0.003782
student       unknown       163    0.003605
technician    primary       158    0.003495
services      unknown       150    0.003318
blue-collar   tertiary      149    0.003296
self-employed primary       130    0.002875
unknown       unknown       127    0.002809
retired       unknown       119    0.002632
entrepreneur  unknown        76    0.001681
unknown       secondary      71    0.001570
              primary        51    0.001128
housemaid     unknown        45    0.000995
student       primary        44    0.000973
self-employed unknown        39    0.000863
unknown       tertiary       39    0.000863
unemployed    unknown        29    0.000641
Resumen estadístico bivariado#

El resumen estadístico bivariado se refiere al estudio de dos variables simultáneamente para determinar si existe alguna relación o asociación entre ellas. Solo realizaremos las tablas para dicho análisis estadístico.

  1. Variable categórica vs variable numérica

# descriptivo edad según la suscripcion solo una variable
df.groupby('y')['age'].mean()

var_num_cat = df.groupby('y')['age'].agg([
    ('Promedio', 'mean'),                       # Media
    ('Desv Estandar', 'std'),                         # Desviación estándar
    ('Minimo', 'min'),                         # Mínimo
    ('Maximo', 'max'),                         # Máximo
    ('Mediana', 'median'),                   # Mediana
    ('Cuantil 1', lambda x: x.quantile(0.25)),   # Cuantil 25%
    ('Cuantil 3', lambda x: x.quantile(0.75))    # Cuantil 75%
])

# Mostrar los resultados
print(var_num_cat)
      Promedio  Desv Estandar  Minimo  Maximo  Mediana  Cuantil 1  Cuantil 3
y                                                                           
no   40.838986      10.172662      18      95     39.0       33.0       48.0
yes  41.670070      13.497781      18      95     38.0       31.0       50.0
# descriptivo edad según la suscripcion varias variable
df.groupby('y')[['age','balance']].mean()

# Resumen descriptivo  de edad según la suscripcion solo una variable
var_num_cat = df.groupby('y')[['age','balance']].agg([
    'mean',                       # Media
    'std',                        # Desviación estándar
    'min',                        # Mínimo
    'max',                        # Máximo
    'median',                     # Mediana
    lambda x: x.quantile(0.25),   # Cuantil 25%
    lambda x: x.quantile(0.75)    # Cuantil 75%
])

# Renombrar las columnas resultantes
var_num_cat.columns = [
    'Edad_Promedio', 'Edad_Desviacion_Estandar', 'Edad_Minimo', 'Edad_Maximo', 'Edad_Mediana', 'Edad_Cuantil_1', 'Edad_Cuantil_3',
    'Balance_Promedio', 'Balance_Desviacion_Estandar', 'Balance_Minimo', 'Balance_Maximo', 'Balance_Mediana', 'Balance_Cuantil_1', 'Balance_Cuantil_3'
]

# imprimir
print(var_num_cat)
     Edad_Promedio  Edad_Desviacion_Estandar  Edad_Minimo  Edad_Maximo  \
y                                                                        
no       40.838986                 10.172662           18           95   
yes      41.670070                 13.497781           18           95   

     Edad_Mediana  Edad_Cuantil_1  Edad_Cuantil_3  Balance_Promedio  \
y                                                                     
no           39.0            33.0            48.0       1303.714969   
yes          38.0            31.0            50.0       1804.267915   

     Balance_Desviacion_Estandar  Balance_Minimo  Balance_Maximo  \
y                                                                  
no                   2974.195473           -8019          102127   
yes                  3501.104777           -3058           81204   

     Balance_Mediana  Balance_Cuantil_1  Balance_Cuantil_3  
y                                                           
no             417.0               58.0             1345.0  
yes            733.0              210.0             2159.0  
Resumen estadístico con tablas dinámicas#

Las tablas dinámicas son otras formas de calcular estadística de resumen agrupada. Por ejemplo

# promedio de la edad según la suscripcion con pivot_table
df.pivot_table(values='age',index='y')

# descriptivo edad según la suscripcion con pivot_table

df.pivot_table(values='age',index='y',aggfunc=['mean','std','min','max','median'])

# Agreaar los cuantiles 1 y 3
def q25(series):
    return np.quantile(series, 0.25)

def q75(series):
    return np.quantile(series, 0.75)

df.pivot_table(values='age',index='y',aggfunc=['mean','std','min','max','median',q25,q75])
mean std min max median q25 q75
age age age age age age age
y
no 40.838986 10.172662 18 95 39.0 33.0 48.0
yes 41.670070 13.497781 18 95 38.0 31.0 50.0

Ahora, usemos pivot_table para dos variables categóricas. Por ejemplo

# Promedio de edad de la variable educación vs empleo
df.pivot_table(values = 'age',index='education', columns='job')
job admin. blue-collar entrepreneur housemaid management retired self-employed services student technician unemployed unknown
education
primary 46.100478 42.294838 44.360656 48.631579 48.605442 62.698113 45.276923 43.756522 22.636364 47.189873 43.073930 47.000000
secondary 39.276843 38.340160 41.583026 43.898734 42.051740 60.058943 41.537262 38.238068 25.779528 39.576975 41.409341 44.436620
tertiary 35.083916 36.664430 41.706997 42.450867 39.735931 62.090164 38.845138 36.227723 28.215247 37.458841 37.788927 47.076923
unknown 45.356725 42.680617 45.671053 52.866667 46.123967 66.008403 43.948718 42.160000 27.687117 43.595041 42.620690 49.755906

Para crear una tabla de contigencia, basta con tener dos variables categóricas. Por ejemplo

# Crear la tabla pivote con conteo de personas
pivot_table = df.pivot_table(
    index='education',
    columns='job',
    aggfunc='size'  # Conteo de entradas
)
print(pivot_table)

# Otra forma de crear una tabla de contingencia
crosstab = pd.crosstab(df['education'], df['job'], margins=True, margins_name='Total')
print(crosstab)
job        admin.  blue-collar  entrepreneur  housemaid  management  retired  \
education                                                                      
primary       209         3758           183        627         294      795   
secondary    4219         5371           542        395        1121      984   
tertiary      572          149           686        173        7801      366   
unknown       171          454            76         45         242      119   

job        self-employed  services  student  technician  unemployed  unknown  
education                                                                     
primary              130       345       44         158         257       51  
secondary            577      3457      508        5229         728       71  
tertiary             833       202      223        1968         289       39  
unknown               39       150      163         242          29      127  
job        admin.  blue-collar  entrepreneur  housemaid  management  retired  \
education                                                                      
primary       209         3758           183        627         294      795   
secondary    4219         5371           542        395        1121      984   
tertiary      572          149           686        173        7801      366   
unknown       171          454            76         45         242      119   
Total        5171         9732          1487       1240        9458     2264   

job        self-employed  services  student  technician  unemployed  unknown  \
education                                                                      
primary              130       345       44         158         257       51   
secondary            577      3457      508        5229         728       71   
tertiary             833       202      223        1968         289       39   
unknown               39       150      163         242          29      127   
Total               1579      4154      938        7597        1303      288   

job        Total  
education         
primary     6851  
secondary  23202  
tertiary   13301  
unknown     1857  
Total      45211  

Indices explicitos#

En Python, los índices son utilizados para acceder a elementos en estructuras de datos como listas, tuplas, y matrices (arrays). Un índice explícito se refiere a la práctica de definir de manera específica el índice que se va a utilizar para acceder a un elemento, en lugar de depender de la indexación automática por la posición.

Características de los Índices Explícitos

  • Flexibilidad: Permiten el acceso a elementos específicos de una estructura de datos sin necesidad de recorrer secuencialmente todos los elementos.

  • Claridad: Facilitan la lectura y comprensión del código al hacer evidente qué elementos se están accediendo o modificando.

  • Manipulación de Datos: Hacen más sencillo realizar operaciones como reordenar elementos, filtrar,seleccionar, agrupar o acceder a subconjuntos de datos.

  • Compatibilidad con Pandas: En bibliotecas como pandas, los índices explícitos son fundamentales para trabajar con Series y DataFrames, permitiendo indexar tanto por números como por etiquetas.

  • Precisión: Al especificar el índice, reduces el riesgo de errores al manipular datos.

  • Eficiencia: Mejoran la eficiencia al permitir operaciones directas sobre los elementos deseados.

Visualicemos nuevamente el dataframe de marketing para la banca.

# marco de datos
df.head()
age job marital education default balance housing loan contact day month duration campaign pdays previous poutcome y
0 58 management married tertiary no 2143 yes no unknown 5 may 261 1 -1 0 unknown no
1 44 technician single secondary no 29 yes no unknown 5 may 151 1 -1 0 unknown no
2 33 entrepreneur married secondary no 2 yes yes unknown 5 may 76 1 -1 0 unknown no
3 47 blue-collar married unknown no 1506 yes no unknown 5 may 92 1 -1 0 unknown no
4 33 unknown single unknown no 1 no no unknown 5 may 198 1 -1 0 unknown no

Analicemos algunas funciones utiles de la indexación explicita:

  • df.set_index(); Este método se usa para establecer una o más columnas del DataFrame como su índice.

# Establecer la columna 'job' como índice
df.set_index('job')
age marital education default balance housing loan contact day month duration campaign pdays previous poutcome y
job
management 58 married tertiary no 2143 yes no unknown 5 may 261 1 -1 0 unknown no
technician 44 single secondary no 29 yes no unknown 5 may 151 1 -1 0 unknown no
entrepreneur 33 married secondary no 2 yes yes unknown 5 may 76 1 -1 0 unknown no
blue-collar 47 married unknown no 1506 yes no unknown 5 may 92 1 -1 0 unknown no
unknown 33 single unknown no 1 no no unknown 5 may 198 1 -1 0 unknown no
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
technician 51 married tertiary no 825 no no cellular 17 nov 977 3 -1 0 unknown yes
retired 71 divorced primary no 1729 no no cellular 17 nov 456 2 -1 0 unknown yes
retired 72 married secondary no 5715 no no cellular 17 nov 1127 5 184 3 success yes
blue-collar 57 married secondary no 668 no no telephone 17 nov 508 4 -1 0 unknown no
entrepreneur 37 married secondary no 2971 no no cellular 17 nov 361 2 188 11 other no

45211 rows × 16 columns

  • df.reset_index():Este método se usa para restablecer el índice del DataFrame, devolviendo los índices actuales a columnas y creando un nuevo índice numérico predeterminado. Si usas el parámetro drop=True indica que se debe eliminar la columna de índice original en lugar de moverla a una columna.

df.reset_index(drop=True)
age job marital education default balance housing loan contact day month duration campaign pdays previous poutcome y
0 58 management married tertiary no 2143 yes no unknown 5 may 261 1 -1 0 unknown no
1 44 technician single secondary no 29 yes no unknown 5 may 151 1 -1 0 unknown no
2 33 entrepreneur married secondary no 2 yes yes unknown 5 may 76 1 -1 0 unknown no
3 47 blue-collar married unknown no 1506 yes no unknown 5 may 92 1 -1 0 unknown no
4 33 unknown single unknown no 1 no no unknown 5 may 198 1 -1 0 unknown no
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
45206 51 technician married tertiary no 825 no no cellular 17 nov 977 3 -1 0 unknown yes
45207 71 retired divorced primary no 1729 no no cellular 17 nov 456 2 -1 0 unknown yes
45208 72 retired married secondary no 5715 no no cellular 17 nov 1127 5 184 3 success yes
45209 57 blue-collar married secondary no 668 no no telephone 17 nov 508 4 -1 0 unknown no
45210 37 entrepreneur married secondary no 2971 no no cellular 17 nov 361 2 188 11 other no

45211 rows × 17 columns

  • df.sort_index(): Este método ordena las filas del DataFrame en función del índice.

# orden de los indices
df.sort_index(ascending=False)
age job marital education default balance housing loan contact day month duration campaign pdays previous poutcome y
45210 37 entrepreneur married secondary no 2971 no no cellular 17 nov 361 2 188 11 other no
45209 57 blue-collar married secondary no 668 no no telephone 17 nov 508 4 -1 0 unknown no
45208 72 retired married secondary no 5715 no no cellular 17 nov 1127 5 184 3 success yes
45207 71 retired divorced primary no 1729 no no cellular 17 nov 456 2 -1 0 unknown yes
45206 51 technician married tertiary no 825 no no cellular 17 nov 977 3 -1 0 unknown yes
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4 33 unknown single unknown no 1 no no unknown 5 may 198 1 -1 0 unknown no
3 47 blue-collar married unknown no 1506 yes no unknown 5 may 92 1 -1 0 unknown no
2 33 entrepreneur married secondary no 2 yes yes unknown 5 may 76 1 -1 0 unknown no
1 44 technician single secondary no 29 yes no unknown 5 may 151 1 -1 0 unknown no
0 58 management married tertiary no 2143 yes no unknown 5 may 261 1 -1 0 unknown no

45211 rows × 17 columns

En conclusión, el uso de índices explícitos en Python es una técnica poderosa que permite un control detallado sobre la manipulación de datos. Ya sea en estructuras simples como listas o en análisis más complejos utilizando pandas, el conocimiento y uso adecuado de índices explícitos puede mejorar significativamente la eficiencia y claridad de tu código.

Visualización sencilla de datos#

Matplotlib es una biblioteca de visualización de datos en Python ampliamente utilizada, especialmente en los campos de la ciencia de datos, la ingeniería y la investigación. Permite crear una amplia gama de gráficos, desde simples gráficos de líneas y dispersión hasta complejas visualizaciones tridimensionales y gráficos interactivos.

Características principales de Matplotlib

  • Flexibilidad: Matplotlib ofrece una amplia personalización en todos los aspectos del gráfico, como colores, tipos de línea, marcadores, etiquetas y leyendas.

  • Versatilidad: Puede generar gráficos estáticos, animados e interactivos en diferentes formatos de archivo, incluyendo PNG, PDF, SVG y más.

  • Compatibilidad: Se integra fácilmente con otras bibliotecas populares como NumPy, pandas y Seaborn, facilitando el análisis y visualización de datos.

  • API orientada a objetos: Matplotlib ofrece una API que permite un control detallado sobre la creación y personalización de gráficos.

Ventajas de Matplotlib

  • Amplia documentación: Matplotlib tiene una documentación extensa y muchos ejemplos, lo que facilita su aprendizaje y uso.

  • Gran comunidad: Existe una gran comunidad de usuarios que contribuyen con ejemplos, tutoriales y soluciones a problemas comunes.

  • Personalización detallada: Permite ajustar prácticamente cualquier aspecto de los gráficos, desde los tamaños de las figuras hasta los estilos de línea y los colores.

Desventajas de Matplotlib

  • Curva de aprendizaje: Aunque poderosa, la flexibilidad de Matplotlib puede resultar intimidante para los principiantes, especialmente cuando se trata de personalizar gráficos complejos.

  • Estética básica: Los gráficos creados con Matplotlib, sin personalización adicional, pueden parecer básicos en comparación con otras bibliotecas como Seaborn o Plotly.

Seaborn es una biblioteca de visualización de datos basada en Matplotlib que proporciona una interfaz de alto nivel para crear gráficos estadísticos atractivos y fáciles de interpretar en Python. Seaborn está diseñada para trabajar bien con estructuras de datos de pandas y ofrece una serie de herramientas avanzadas para el análisis visual, lo que la convierte en una opción popular entre los científicos de datos, analistas y desarrolladores.

Principales Características de Seaborn:

  • Interfaz de Alto Nivel: Seaborn simplifica la creación de gráficos al proporcionar funciones de alto nivel que requieren menos código que Matplotlib para realizar tareas similares. Esto permite generar gráficos complejos con menos esfuerzo.

  • Integración con Pandas: Seaborn trabaja de manera eficiente con los DataFrames de Pandas, lo que permite pasar directamente las columnas del DataFrame como entrada para crear gráficos. También es capaz de manejar automáticamente las leyendas y los ejes con nombres de variables.

  • Paletas de Colores Personalizables: Seaborn ofrece varias paletas de colores prediseñadas que facilitan la creación de gráficos estéticamente agradables. También permite personalizar las paletas de colores para adaptarse a diferentes estilos y necesidades.

  • Visualización de Relaciones Estadísticas: Seaborn está diseñado para mostrar las relaciones estadísticas subyacentes en los datos. Por ejemplo, puede crear gráficos de regresión, gráficos de dispersión, gráficos de correlación, entre otros.

  • Visualización de Datos Categóricos: Seaborn proporciona varias funciones para crear gráficos que muestran datos categóricos, como barplot, countplot, boxplot, violinplot, entre otros.

  • Visualización de Distribuciones de Datos: Seaborn facilita la visualización de distribuciones de datos utilizando gráficos como el histograma (histplot), gráficos de densidad de kernel (KDE), y gráficos de distribución conjunta (jointplot).

  • Gráficos de Facetas: Con Seaborn, es posible crear gráficos de facetas que muestran múltiples gráficos en una sola figura para diferentes subconjuntos de datos. Esto es particularmente útil para la visualización exploratoria de datos y el análisis multivariado.

Temas de Estilo Integrados: Seaborn tiene temas de estilo incorporados como darkgrid, whitegrid, dark, white, y ticks, que se pueden aplicar fácilmente a los gráficos para mejorar la estética.

Para el desarrollo de las visualización trabajaremos con datos sobre los almacenes Walmart, que es un cadena de grande almacenes de Ewa.

_images/walmart.png

El conjunto de datos completos lo puede encontrar este link. Trabajaremos un subconjunto de datos contiene las ventas semanales en dolares, cada tienda tiene un número de identificación y un tipo de tienda específico, las ventas estan separadas por ID de departamento. Junto con las ventas hay variables como si fue de vacaciones o no, la temperatura media durante la semana en esa localidad, el tiempo medio del combustible en dolares por litro esa semana y la tasa de desempleo de esa semana

Aquí tienes una explicación de las variables en el conjunto de datos de ventas proporcionado:

  • Unnamed: Columna de índice que parece haber sido incluida al guardar el archivo. No es una variable significativa.

  • store: Identificador del número de la tienda.

  • type: Tipo de tienda, representado por una letra (por ejemplo, “A”, “B”, etc.).

  • department: Identificador del número de departamento dentro de la tienda.

  • date: Fecha en la que se registró la venta.

  • weekly_sales: Ventas semanales en USD registradas en esa tienda y departamento específicos.

  • is_holiday: Variable booleana que indica si la fecha corresponde a un día festivo o no. Los valores son “True” o “False”.

  • temperature_c: Temperatura en grados Celsius en la fecha registrada.

  • fuel_price_usd_per_l: Precio del combustible en dólares estadounidenses por litro en la fecha registrada.

  • unemployment: Tasa de desempleo en la fecha registrada.

Carguemos el conjunto de datos:

df =  pd.read_csv('_data/datamanip/sales.csv')
df.head()
Unnamed: 0 store type department date weekly_sales is_holiday temperature_c fuel_price_usd_per_l unemployment
0 0 1 A 1 2010-02-05 24924.50 False 5.727778 0.679451 8.106
1 1 1 A 1 2010-03-05 21827.90 False 8.055556 0.693452 8.106
2 2 1 A 1 2010-04-02 57258.43 False 16.816667 0.718284 7.808
3 3 1 A 1 2010-05-07 17413.94 False 22.527778 0.748928 7.808
4 4 1 A 1 2010-06-04 17558.09 False 27.050000 0.714586 7.808
# Renombrar una columna
df.rename(columns={'Unnamed: 0': 'id'}, inplace=True)
df.head()
id store type department date weekly_sales is_holiday temperature_c fuel_price_usd_per_l unemployment
0 0 1 A 1 2010-02-05 24924.50 False 5.727778 0.679451 8.106
1 1 1 A 1 2010-03-05 21827.90 False 8.055556 0.693452 8.106
2 2 1 A 1 2010-04-02 57258.43 False 16.816667 0.718284 7.808
3 3 1 A 1 2010-05-07 17413.94 False 22.527778 0.748928 7.808
4 4 1 A 1 2010-06-04 17558.09 False 27.050000 0.714586 7.808
# Informacion del conjunto de datos
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10774 entries, 0 to 10773
Data columns (total 10 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   id                    10774 non-null  int64  
 1   store                 10774 non-null  int64  
 2   type                  10774 non-null  object 
 3   department            10774 non-null  int64  
 4   date                  10774 non-null  object 
 5   weekly_sales          10774 non-null  float64
 6   is_holiday            10774 non-null  bool   
 7   temperature_c         10774 non-null  float64
 8   fuel_price_usd_per_l  10774 non-null  float64
 9   unemployment          10774 non-null  float64
dtypes: bool(1), float64(4), int64(3), object(2)
memory usage: 768.2+ KB

Matplotlib es especialmente útil cuando necesitas crear gráficos personalizados y detallados, y es una herramienta esencial para cualquier persona que trabaje con visualización de datos en Python. Haremos unas gráficas univariadas

Histograma#

Un histograma es una representación gráfica que muestra la distribución de una variable continua. Se divide el rango de valores en intervalos (bins) y se cuenta cuántos valores caen en cada intervalo.

Características del histograma

  • Ideal para visualizar la forma de la distribución de los datos.

  • Ayuda a identificar la simetría, la dispersión, y la presencia de outliers.

  • El número de bins afecta la interpretación; demasiados o muy pocos bins pueden ocultar patrones importantes.

  • Permite una fácil visualización de la distribución de datos.

  • Útil para identificar la presencia de sesgos en los datos.

  • No es útil para datos categóricos.

# importar matplotlib
import matplotlib.pyplot as plt

# Histograma de las ventas semanales
plt.hist(df['fuel_price_usd_per_l'])
plt.show()
_images/1c9c907f037b105dd538d4c59cf8d5b2afc2db673d2ca6a9f6e04374f7ea6b37.png
# Otra forma
df['weekly_sales'].hist()
plt.show()
_images/06ce8a449db238af43e1a9ed2fc2c8bbbf1e33c9d6700cd132fc7140d5b6f98b.png
import warnings
warnings.filterwarnings("ignore")
# Importar seaborn
import seaborn as sns

# Histograma de las ventas semanales con Seaborn
sns.histplot(df['fuel_price_usd_per_l'], kde=False)  # kde=True si quieres agregar la densidad
plt.show()
_images/8cdfa067eaebea43053f9b17487ae2ef4d114add3b92e64e653fb0188d15c12f.png
# Histograma del precio del combustible ajustando el bins = 20
df['fuel_price_usd_per_l'].hist(bins=20)
plt.show()
_images/9cfee98404a78f58c62037812ce006624b75e81fa63d1cfa3eb118c5e9e12ce7.png

Densidad#

Una gráfica de densidad es una representación gráfica suave de la distribución de una variable continua. Se basa en la estimación de la función de densidad de probabilidad (KDE, por sus siglas en inglés), lo que permite visualizar la forma general de la distribución sin depender de intervalos rígidos como en los histogramas.

Características de la gráfica de densidad

  • Ideal para visualizar la forma suave de la distribución de los datos.

  • Útil para comparar distribuciones entre varios grupos.

  • No requiere la definición de bins, a diferencia del histograma.

  • Permite identificar modas (picos), simetría, y presencia de sesgos.

  • Es sensible al parámetro de suavizado (bandwidth), el cual afecta la forma de la curva.

  • A diferencia del histograma, muestra una curva continua.

  • No es útil para datos categóricos.

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde

# Estimación de densidad usando KDE
kde = gaussian_kde(df['fuel_price_usd_per_l'].dropna())
x_vals = np.linspace(min(data), max(data), 1000)
y_vals = kde(x_vals)

# Gráfico
plt.figure(figsize=(8, 4))
plt.plot(x_vals, y_vals, color='blue', lw=2, label='Densidad KDE')
plt.fill_between(x_vals, y_vals, alpha=0.3, color='blue')
plt.title('Gráfica de densidad de precio del combustible (Matplotlib + SciPy)')
plt.xlabel('Precio USD por litro')
plt.ylabel('Densidad')
plt.legend()
plt.grid(True)
plt.show()
_images/efcfdc2a5717cab5eb7ba3781407c23b147e2168632c824416a79435c1444a44.png
import seaborn as sns
import matplotlib.pyplot as plt

# Gráfico de densidad
plt.figure(figsize=(8, 4))
sns.kdeplot(df['fuel_price_usd_per_l'], fill=True, color='green', linewidth=2, label='Densidad KDE')
plt.title('Gráfica de densidad de precio del combustible (Seaborn)')
plt.xlabel('Precio USD por litro')
plt.ylabel('Densidad')
plt.legend()
plt.grid(True)
plt.show()
_images/107555ed2e516e10b088d232379ba6b520eae5a4abda5cf805c43a27f6c3c9f1.png

Histograma con función de densidad#

Un histograma con función de densidad combina la representación clásica del histograma (que agrupa los datos en intervalos) con una curva de densidad suave (estimación KDE). Esta combinación permite visualizar tanto la frecuencia aproximada de los valores como la forma general de la distribución de los datos.

Características del histograma con función de densidad

  • Combina la vista detallada del histograma con la suavidad de la curva de densidad.

  • Útil para observar la frecuencia de los datos junto con la tendencia general.

  • Permite detectar sesgos, modas, simetría, y posibles valores atípicos.

  • El número de bins influye en la forma del histograma; la curva de densidad ayuda a suavizar esa variabilidad.

  • La curva KDE puede verse afectada por el parámetro de suavizado (bandwidth).

  • Ideal para explorar la distribución de variables continuas.

# KDE
kde = gaussian_kde(df['fuel_price_usd_per_l'].dropna())
x_vals = np.linspace(min(data), max(data), 1000)
y_vals = kde(x_vals)

# Gráfico
plt.figure(figsize=(8, 4))
plt.hist(data, bins=30, density=True, alpha=0.4, color='skyblue', label='Histograma')
plt.plot(x_vals, y_vals, color='darkblue', lw=2, label='Densidad KDE')
plt.title('Histograma con curva de densidad')
plt.xlabel('Precio USD por litro')
plt.ylabel('Densidad')
plt.legend()
plt.grid(True)
plt.show()
_images/dfae611dd1b0e72b799b27c84d992c9a738aed55b908c824aa18be7752f935ec.png
# Gráfico
plt.figure(figsize=(8, 4))
sns.histplot(df['fuel_price_usd_per_l'], kde=True, bins=30, color='darkgreen', edgecolor='black')
plt.title('Histograma con curva de densidad (Seaborn)')
plt.xlabel('Precio USD por litro')
plt.ylabel('Densidad')
plt.grid(True)
plt.show()
_images/24e319c90bd3761b5761d55a25b3296b2533eee83f8984fd0b2d619dba0cbbe4.png
  • Una transformación logarítmica ayuda a identificar más tendencias. Por ejemplo, en el siguiente gráfico, el eje muestra los valores transformados en logaritmos de la variable del precio, y vemos que hay dos o más picos que indican el precio de la gasolina por litro

# Aplicar logaritmo y eliminar valores no válidos
log_data = np.log(df['fuel_price_usd_per_l'].dropna())

# KDE
kde = gaussian_kde(log_data)
x_vals = np.linspace(min(log_data), max(log_data), 1000)
y_vals = kde(x_vals)

# Gráfico
plt.figure(figsize=(8, 4))
plt.hist(log_data, bins=30, density=True, alpha=0.4, color='skyblue', label='Histograma (log)')
plt.plot(x_vals, y_vals, color='darkblue', lw=2, label='Densidad KDE')
plt.title('Histograma con curva de densidad (Log precios)')
plt.xlabel('Log(Precio USD por litro)')
plt.ylabel('Densidad')
plt.legend()
plt.grid(True)
plt.show()
_images/a6dff50718e97b4468cc1e78fccfe31b6a09ca8c9cf960bcbbc1ad8e527ffa4d.png
# Datos transformados
log_data = np.log(df['fuel_price_usd_per_l'].dropna())

# Gráfico
plt.figure(figsize=(8, 4))
sns.histplot(log_data, kde=True, bins=30, color='lightgreen', edgecolor='black')
plt.title('Histograma con Curva de Densidad (Log Precios)')
plt.xlabel('Log(Precio USD por litro)')
plt.ylabel('Densidad')
plt.grid(True)
plt.show()
_images/f5d6ba9063ba9a02cfbfa6e9a5109021c9bc4b1e14037c82651439315145ecea.png

Cajas y bigotes#

Un gráfico de cajas y bigotes visualiza la distribución de un conjunto de datos, mostrando la mediana y los cuartiles, así como los posibles outliers.

Características de la cajas y bigotes

  • Caja: Representa el rango intercuartil (IQR), es decir, el 50% central de los datos, entre el primer y el tercer cuartil (Q1 y Q3).

  • Línea dentro de la caja: Representa la mediana (Q2) de los datos.

  • Bigotes: Se extienden desde los cuartiles hasta el valor más pequeño y el más grande dentro de 1.5 veces el IQR. Los valores fuera de este rango se consideran outliers y se marcan como puntos individuales.

  • Outliers: Valores que caen fuera de los bigotes y son indicados por puntos individuales.

Ventajas

  • Resúmenes concisos: Muestra un resumen estadístico claro en un formato gráfico compacto.

  • Detección de outliers: Facilita la identificación de valores atípicos o extremos.

  • Comparación entre grupos: Permite comparar la distribución de datos entre diferentes grupos o categorías de manera efectiva.

# diagrama de cajas y bigotes de la temperatura
plt.boxplot(df['temperature_c'])

# Remover el nombre de la columna del eje X
plt.xticks([1], [''])  

# Agregar título y etiquetas
plt.title('Gráfico de Cajas y Bigotes')
plt.ylabel('Temperatura (°F)')

# Mostrar el gráfico
plt.show()
_images/2c9eea89ec4ce1ff137af3aa4903515089b83e7d0ccef65fbb30b941c188bfac.png
# otra forma
df.boxplot(column = 'temperature_c')

# Remover el nombre de la columna del eje X
plt.xticks([1], [''])  

# Agregar título y etiquetas
plt.title('Gráfico de Cajas y Bigotes')
plt.ylabel('Temperatura (°F)')

# Mostrar el gráfico
plt.show()
_images/90c7b6b5926626b8a6995a47c2e7cfd3a3d54f712e0bec1b68a43f6b3bcdbfd9.png
# Crear un diagrama de cajas y bigotes con Seaborn
sns.boxplot(x=df['temperature_c'])

# Remover el nombre de la columna del eje X
plt.xticks([0], [''])

# Agregar título y etiquetas
plt.title('Gráfico de Cajas y Bigotes')
plt.ylabel('Temperatura (°C)')
Text(0, 0.5, 'Temperatura (°C)')
_images/650ddca3be35f67914c562a006d864dc55fc2b77cc668965a0d833ab14b84045.png

Barras#

Una gráfica de barras se utiliza para mostrar y comparar cantidades entre diferentes categorías. Cada barra representa una categoría, y su altura es proporcional al valor que representa.

Características de las barras

  • Adecuada para datos categóricos.

  • Las barras pueden organizarse horizontal o verticalmente. Fácil de interpretar y comparar diferentes categorías.

  • Proporciona una clara visualización de las diferencias entre categorías.

  • Fácil de leer e interpretar, incluso con muchas categorías.

# Contar el tipo de tienda
tipo = df['type'].value_counts() 

# Graficar el conteo de tipos de tienda en un gráfico de barras verticales
plt.bar(tipo.index, tipo.values)
plt.show()
_images/7f2b7a13ac2698bff57110462cc6290283c2236b504544ea29d02696ebead987.png
# Graficar el conteo de tipos de tienda en un gráfico de barras con Seaborn
sns.countplot(x='type', data=df)

# Agregar título y etiquetas si lo deseas
plt.title('Conteo de tipos de tienda')
plt.xlabel('Tipo de tienda')
plt.ylabel('Frecuencia')

# Mostrar el gráfico
plt.show()
_images/287c515f10aa6a92d6102bd6b603f96be23de306cb79d746dae82bd284a78b76.png
# Convertir is_holiday en categorica
festivo = df['is_holiday'].map({True: 'Holiday', False: 'Non-Holiday'}).astype('category')

# Contar el tipo de tienda
conteo_festivo = festivo.value_counts() 

#Graficar el conteo de festivos en un gráfico de barras verticales
plt.barh(conteo_festivo.index, conteo_festivo.values)
plt.show()
_images/a59deb3126c42fe1cb857aaf8dc209f98046cc18e448e41919b080b3fe086af1.png
# Contar el tipo de festividad
conteo_festivo = festivo.value_counts().reset_index()
conteo_festivo.columns = ['Festivo', 'Conteo']

# Graficar el conteo de festividades en un gráfico de barras horizontal con Seaborn
sns.barplot(x='Conteo', y='Festivo', data=conteo_festivo, orient='h')

# Agregar título y etiquetas si lo deseas
plt.title('Conteo de festividades')
plt.xlabel('Conteo')
plt.ylabel('Festivo')

# Mostrar el gráfico
plt.show()
_images/6b050d7aa559b9d8d719918167046d17f92388b0ddd8201fec6bf1a30ac5af11.png

Otras forma de realizar gráficos de barras#

Aprenderemos a crear una tabla utilizando la función pandas crosstab. Utilizaremos una tabla para generar un gráfico de barras. A continuación, exploraremos un gráfico de barras generado con la biblioteca seaborn y calcularemos la distribución del promedio de weekly_sales según el store. Para ello, vamos a realizar los siguientes pasos:

  • Imprime los valores únicos de la columna corte. usemos unique() devuelve un array. El número de valores únicos se puede obtener utilizando nunique() en pandas.

print(df.store.unique())
print(df.store.nunique())
[ 1  2  4  6 10 13 14 19 20 27 31 39]
12
  • Para obtener los recuentos de las stores, primero creamos una tabla utilizando la función pandas crosstab():

store_count_table = pd.crosstab(index = df['store'], columns = 'count')
store_count_table
col_0 count
store
1 901
2 897
4 901
6 894
10 902
13 913
14 885
19 906
20 910
27 900
31 890
39 875
  • Pase estos recuentos a otra función pandas, plot(kind='bar'):

store_count_table.plot(kind = 'bar');
_images/63f467ad15859aacc74c2cf413534b375357bb9169dfa4be5291c250d342372e.png
  • Generemos el mismo gráfico con seaborn

# Preparar los datos
store_counts = store_count_table.reset_index()

# Graficar
plt.figure(figsize=(10, 5))
sns.barplot(data=store_counts, x='store', y='count', color='salmon')
plt.title('Conteo de registros por tienda (desde tabla)')
plt.xlabel('Tienda')
plt.ylabel('Cantidad')
plt.xticks(rotation=45)
plt.grid(True, axis='y', linestyle='--', alpha=0.5)
plt.show()
_images/1b60b7de352034734a57aa76259570bbaccd8a9b5929b9a0d021e6ded61eab29.png
  • Usemos catplot de seaborn

sns.catplot(data = df, x = 'store', aspect = 1.5, kind = "count", color = "b");
_images/b0d12b07caeb5a39330ea0f36d725ab284b5acf06ce7c6e839579b106f359d43.png

Observe cómo la función catplot() no requiere que creemos la tabla de recuento intermedia (utilizando pd.crosstab()), y reduce un paso en el proceso de trazado.

  • A continuación, se muestra cómo se obtiene la distribución del precio medio semanal de las diferentes calidades de tiendas utilizando seaborn

from numpy import median, mean

sns.set(style = "whitegrid")
ax = sns.barplot(x = "store", y = "weekly_sales", data = df, estimator = mean,color="skyblue");
_images/bbc087964311c472277d5d0a48fc65a2259b4a63875d82aef53257489ef8e97b.png

Aquí, las líneas negras (barras de error) de los rectángulos indican la incertidumbre (o dispersión de los valores) en torno a la estimación de la media. Las funciones mencionadas van mucho más allá de un simple recuento: aplican una función que calcula una medida de tendencia central (por defecto es el valor medio) y muestran, aplicando bootstrapping, el intervalo de confianza del \(95%\) para dicha medida. Por defecto, este valor está fijado en un \(95%\) de confianza. ¿Cómo lo cambiamos? Utilizando el parámetro ci=68, por ejemplo, lo fijamos en el \(68%\). También podemos representar la desviación estándar en los precios utilizando ci=sd.

  • Reordenar las barras del eje x utilizando el orden:

ax = sns.barplot(x = "store", y = "weekly_sales", data = df, estimator = mean, ci = 68,color="#8FD694", 
                 order = [31, 39,19, 1, 6,27, 13, 10,4, 2, 20, 14]);
_images/370597c31bf04e76a595bb81ac5256ed508b6c27395d558c4e32e7707b86bcac.png
  • Ahora, veamos un gráfico de barras agrupada. Utilice el parámetro hue para trazar grupos anidados:

ax = sns.barplot(x = "store", y = "weekly_sales", hue = 'is_holiday', data = df, estimator = mean,);
_images/48f6a16104b6dbfcc6447f96abe3d30fb5a0c005ab0a2081fb971383d0d8fe6b.png
  • Si deseamos poner notas en diagrama de barras.

from numpy import mean
import seaborn as sns
import matplotlib.pyplot as plt

sns.set(style="whitegrid")

plt.figure(figsize=(10, 5))
ax = sns.barplot(
    x="store",
    y="weekly_sales",
    data=df,
    estimator=mean,
    color="#8FD694"
)

# Encuentra la tienda con mayores ventas promedio
mean_sales = df.groupby("store")["weekly_sales"].mean()
top_store = mean_sales.idxmax()
top_value = mean_sales.max()
x = list(mean_sales.index).index(top_store)  # posición de la barra en el eje x
y = top_value  # altura de la barra

# Anotación con nota visual
plt.annotate(
    'Excelente desempeño máximas ventas promedio',
    xy=(x, y),
    xytext=(x + 0.5, y + 2000),
    bbox=dict(boxstyle='round,pad=0.5', fc='lightyellow', ec='gold', lw=1.5),
    fontsize=10,
    arrowprops=dict(arrowstyle='->', color='red',linewidth=2),
)

plt.title("Promedio de ventas semanales por tienda")
plt.xlabel("Tienda")
plt.ylabel("Weekly Sales")
plt.show()
_images/4d22c8c891cde4a8d345d6d6d1132dfe3c92eff88af2428c9961b643c4fac160.png

Circulares#

Un diagrama circular (o gráfico de pastel) es una representación gráfica que muestra la proporción de diferentes categorías dentro de un conjunto de datos como segmentos de un círculo. Cada segmento del círculo representa una categoría y su tamaño es proporcional a su frecuencia o porcentaje en relación con el total.

Características del diagrama circular

  • Segmentos: Cada porción del círculo corresponde a una categoría y muestra su proporción respecto al total.

  • Proporciones: La suma de todos los segmentos representa el 100% del conjunto de datos.

  • Etiquetas: A menudo se etiquetan los segmentos con nombres de categorías y porcentajes.

Ventajas

  • Visualización clara: Facilita la comprensión de las proporciones de las categorías en un solo vistazo.

  • Comparación intuitiva: Permite comparar rápidamente las partes del total.

  • Atractivo visual: Los gráficos de pastel son visualmente atractivos y pueden ser útiles para presentaciones y informes.

Desventaja

  • Dificultad con muchas categorías: No es ideal para conjuntos de datos con muchas categorías, ya que los segmentos pueden volverse difíciles de distinguir.

Para crear un diagrama circular debemos tener en cuenta los siguientes parámetros:

plt.pie(tipo, labels=tipo.index, autopct='%1.1f%%', startangle=140, colors=plt.cm.Paired(range(len(tipo)))) 

genera el diagrama circular:

  • tipo contiene los valores de conteo de cada categoría.

  • labels=tipo.index asigna etiquetas a cada segmento del gráfico.

  • autopct='%1.1f%%' muestra los porcentajes en cada segmento.

  • startangle=140 rota el gráfico para una mejor presentación.

  • colors=plt.cm.Paired(range(len(tipo))) usa un mapa de colores para diferenciar los segmentos.

tipo = df['type'].value_counts()

# Graficar el conteo de tipos de tienda en un diagrama circular
plt.pie(tipo, labels=tipo.index, autopct='%1.1f%%', startangle=140, colors=plt.cm.Paired(range(len(tipo))))
plt.title('Distribución de tipos de tienda')
plt.show()
_images/f983363e9689c8e1d34fb83c34a40afa8caf7bbb7f6be0d701fa4baf0e936ea3.png
# Establecer el estilo de Seaborn
sns.set(style="whitegrid")

# Contar el tipo de tienda
tipo = df['type'].value_counts()

# Graficar el conteo de tipos de tienda en un diagrama circular
plt.figure(figsize=(8, 8))
plt.pie(tipo, labels=tipo.index, autopct='%1.1f%%', startangle=140, colors=sns.color_palette('Paired', len(tipo)))
plt.title('Distribución de tipos de tienda')

# Mostrar el gráfico
plt.show()
_images/62d19df3903f112c7fb57c6d30f53c2832fc4a01cb7344e7ced06af0ac8aba7c.png

Ahora haremos unas gráficas bivariadas.

Lineas#

Una gráfica de líneas conecta una serie de puntos de datos con líneas, generalmente utilizada para mostrar cambios o tendencias a lo largo del tiempo.

Características del diagrama de lineas

  • Ideal para series temporales.

  • Muestra la tendencia general de los datos.

  • Puede incluir múltiples líneas para comparar diferentes series de datos.

Ventajas

  • Excelente para visualizar tendencias a lo largo del tiempo.

  • Permite comparar fácilmente varias series de datos.

Desventajas

  • Puede volverse confusa si se incluyen demasiadas líneas.

  • No es adecuada para datos categóricos.

# Convertir la columna date a formato de fecha
df['date'] = pd.to_datetime(df['date'])

# Agrupar las ventas por fecha, sumando las ventas semanales en las fechas repetidas
df_grouped = df.groupby('date').agg({'weekly_sales': 'sum'}).reset_index()

df_grouped.head()
date weekly_sales
0 2010-02-05 22835369.84
1 2010-02-12 644.77
2 2010-02-19 15.39
3 2010-02-26 10.47
4 2010-03-05 20862754.07
# Crear un gráfico de líneas con las fechas agrupadas
plt.plot(df_grouped['date'], df_grouped['weekly_sales'])

# Rotar las etiquetas del eje X para que se muestren en vertical
plt.xticks(rotation=90)
# Mostrar el gráfico
plt.show()
_images/13be0eb7aa4bfc4645b9280092510c82acc0606b2b1b4c192f641318d0c39fe9.png
# Crear un gráfico de líneas con las fechas agrupadas utilizando Seaborn
plt.figure(figsize=(12, 6))  # Ajustar el tamaño del gráfico
sns.lineplot(x='date', y='weekly_sales', data=df_grouped)

# Rotar las etiquetas del eje X para que se muestren en vertical
plt.xticks(rotation=90)

# Agregar título y etiquetas si lo deseas
plt.title('Ventas semanales agrupadas por fecha')
plt.xlabel('Fecha')
plt.ylabel('Ventas semanales')

# Mostrar el gráfico
plt.show()
_images/e5dde3dcaf6433bae38ecd3f27da69cfe7c11aa2a083f4baa00013361ca613e3.png

Dispersión (Scatter Plots)#

Una gráfica de dispersión muestra la relación entre dos variables numéricas mediante puntos dispersos en un plano cartesiano.

Características del diagrama de dispersión

  • Muestra cómo se correlacionan dos variables.

  • Los patrones de dispersión pueden indicar la relación entre las variables, como linealidad o agrupaciones.

  • Cada punto representa una observación individual.

Ventajas

  • Ideal para identificar relaciones o correlaciones entre dos variables.

  • Permite visualizar la distribución y posibles outliers.

Desventajas

  • No es adecuada para más de dos variables sin técnicas adicionales.

  • Si hay demasiados puntos, puede volverse difícil de interpretar.

# Crear una gráfica de dispersión de wee
df.plot(x='weekly_sales', y='fuel_price_usd_per_l', kind='scatter')
plt.title('Relación entre ventas semanales y precio de la gasolina')
plt.xlabel('Precio de ventas ($)')
plt.ylabel('Precio de la gasolina (kg)')
plt.show()
_images/1f603d55a743f57f3ffa8eaab01b2a7cc9c0ce53c79356a125696e8f8d7de222.png
# Crear una gráfica de dispersión de ventas semanales vs. precio de la gasolina utilizando Seaborn
plt.figure(figsize=(10, 6))  # Ajustar el tamaño del gráfico
sns.scatterplot(x='weekly_sales', y='fuel_price_usd_per_l', data=df)

# Agregar título y etiquetas
plt.title('Relación entre ventas semanales y precio de la gasolina')
plt.xlabel('Ventas semanales ($)')
plt.ylabel('Precio de la gasolina (USD por litro)')

# Mostrar el gráfico
plt.show()
_images/5f4799fcfb3b848a24f9441644fc0311239e91f783f7a80adb3b9761209dc293.png

Histogramas con variable categórica#

Para hacer estos histogramas debemos tener una variable numérica según una variable categórica

# Crear una superposición de histogramas
df[df['type'] == 'A']['weekly_sales'].hist(alpha=0.7, color='blue')
df[df['type'] == 'B']['weekly_sales'].hist(alpha=0.7, color='red')
plt.legend(['A', 'B'])
plt.title('Distribución de las ventas semanales según el tipo')
plt.xlabel('Precio ($)')
plt.ylabel('Frecuencia')
plt.show()
_images/f341c905a296cc8553c907b2815b9eb598575dc3832b3e757cdaa59168f47d09.png
# Crear una superposición de histogramas de las ventas semanales según el tipo de tienda utilizando Seaborn
plt.figure(figsize=(10, 6))  # Ajustar el tamaño del gráfico

# Histograma para el tipo 'A'
sns.histplot(df[df['type'] == 'A']['weekly_sales'], color='blue', label='A', kde=False, alpha=0.7)

# Histograma para el tipo 'B'
sns.histplot(df[df['type'] == 'B']['weekly_sales'], color='red', label='B', kde=False, alpha=0.7)

# Agregar título y etiquetas
plt.title('Distribución de las ventas semanales según el tipo')
plt.xlabel('Ventas semanales ($)')
plt.ylabel('Frecuencia')

# Mostrar la leyenda
plt.legend()
<matplotlib.legend.Legend at 0x23822fc9250>
_images/d61bf94aa42d02b7b15169c3545a92785601fdde7cb33a437bf50783709a77e8.png

Cajas y bigotes con variable categórica#

Para hacer estos diagramas de cajas y bigotes debemos tener una variable numérica según una variable categórica

# Separar los datos por sexo
u_a = df[df['type'] == 'A']['unemployment']
u_b = df[df['type'] == 'B']['unemployment']

# Crear un diagrama de cajas y bigotes para 'height_cm' vs 'sex' usando pandas
plt.boxplot([u_a, u_b], labels=['A', 'B'])

# Agregar título y etiquetas
plt.title('Diagrama de cajas y bigotes: tasa de desempleo según el tipo')
plt.xlabel('Sexo')
plt.ylabel('Altura (cm)')

# Mostrar el gráfico
plt.show()
_images/a7b988ce857c2614fddc5c49c7e9fad2935ede9baa7cf2622f073d072489e1e8.png
# Crear un diagrama de cajas y bigotes para 'unemployment' vs 'type' usando Seaborn
plt.figure(figsize=(10, 6))  # Ajustar el tamaño del gráfico

sns.boxplot(x='type', y='unemployment', data=df)

# Agregar título y etiquetas
plt.title('Diagrama de cajas y bigotes: tasa de desempleo según el tipo')
plt.xlabel('Tipo de tienda')
plt.ylabel('Tasa de desempleo')

# Mostrar el gráfico
plt.show()
_images/69f4b118c9ca7cd5a6061ba01a439bb90ebbca9fee642114842646eed951db4f.png
  • ¿Y si pudiéramos obtener una pista sobre la distribución completa de una característica numérica específica agrupada por otras características categóricas? El tipo de técnica de visualización adecuada en este caso es un gráfico de violín. Un gráfico de violín es similar a un grafico de caja pero incluye más detalles sobre las variaciones de los datos.

# Crear un diagrama de violín para 'unemployment' vs 'type'
plt.figure(figsize=(10, 6))  # Tamaño del gráfico

sns.violinplot(x='type', y='unemployment', data=df, inner='box', palette='pastel')

# Agregar título y etiquetas
plt.title('Distribución de la tasa de desempleo según el tipo de tienda')
plt.xlabel('Tipo de tienda')
plt.ylabel('Tasa de desempleo')

# Mostrar el gráfico
plt.show()
_images/a0bcb618301b93e93d2a6db1843ea279a0e8f84335b53721e26b86093862b641.png

Diagrama de barras con variables categóricas#

Realizaremos un diagrama de barras con dos variables categóricas

# Convertimos 'is_holiday' a categoría con valores 'Holiday' y 'Non-Holiday'
df['is_holiday'] = df['is_holiday'].map({True: 'Holiday', False: 'Non-Holiday'}).astype('category')
# Contar la frecuencia de cada combinación de 'type' y 'is_holiday' y desapilamos
grouped_data = df.groupby(['type', 'is_holiday'], observed=True).size().unstack()

# Crear el gráfico de barras sin apilar
grouped_data.plot(kind='bar', stacked=False)

# Personalización del gráfico
plt.title('Frecuencia de tipo en función de los dias feriados o no')
plt.xlabel('Tipo')
plt.ylabel('Frecuencia')
plt.xticks(rotation=0)

# Mostrar el gráfico
plt.show()
_images/897a5a499d803586c1199b63bf27c1d387bed5d2b639a00cf0757e80d8d74479.png
# Convertir el DataFrame a formato largo (long format) para Seaborn
melted_data = grouped_data.reset_index().melt(id_vars='type', value_vars=['Holiday', 'Non-Holiday'], 
                                              var_name='is_holiday', value_name='count')

# Crear el gráfico de barras no apiladas utilizando Seaborn
plt.figure(figsize=(10, 6))  # Ajustar el tamaño del gráfico
sns.barplot(x='type', y='count', hue='is_holiday', data=melted_data)

# Personalización del gráfico
plt.title('Frecuencia de Tipo en Función de los Días Feriados o No')
plt.xlabel('Tipo de Tienda')
plt.ylabel('Frecuencia')
plt.xticks(rotation=0)

# Mostrar el gráfico
plt.show()
_images/fbf5c73c81862be7b79f741b3687a49353794436a3086aeab16d75aa73b01c91.png

Para exportar las gráficas en formato png. Usamos savefig:

# Contar la frecuencia de cada combinación de 'type' y 'is_holiday' y desapilamos
grouped_data = df.groupby(['type', 'is_holiday'], observed=True).size().unstack()

# Crear el gráfico de barras sin apilar
grouped_data.plot(kind='bar', stacked=False)

# Personalización del gráfico
plt.title('Frecuencia de tipo en función de los dias feriados o no')
plt.xlabel('Tipo')
plt.ylabel('Frecuencia')
plt.xticks(rotation=0)

# exportar la figura
plt.savefig('_image/grafica_1.png',transparent=False)

# exportar la figura con transparencia
plt.savefig('_image/grafica_2.png', transparent=True)
_images/897a5a499d803586c1199b63bf27c1d387bed5d2b639a00cf0757e80d8d74479.png

Este módulo ha proporcionado una base sólida en la importación, manipulación y visualización de datos en Python. Las habilidades adquiridas permitirán crear visualizaciones efectivas que faciliten la interpretación y comunicación de los datos, y la capacidad de manipular y preparar datos adecuadamente es esencial para realizar análisis significativos. La combinación de pandas para la manipulación de datos y Matplotlib para la visualización forma una potente herramienta en el análisis de datos y ciencia de datos.

Diagrama hexagonal#

Existe una versión más elegante de los gráficos de dispersión, llamada hexagonal binning plot (hexbin plot). En este ejercicio, utilizaremos Seaborn para crear una gráfica de dispersión hexagonal (Hexbin Plot) que muestre la relación entre las ventas semanales (weekly_sales) y el precio de la gasolina en USD por litro (fuel_price_usd_per_l). Este gráfico es útil para representar la densidad de datos cuando estos se superponen.

  1. Importemos las bibliotecas necesarias:

import seaborn as sns
import matplotlib.pyplot as plt
  1. Usaremos sns.scatterplot para crear una gráfica de dispersión, y añadiremos un esquema de color personalizado para mejorar la visualización.

import warnings
warnings.filterwarnings("ignore", category=FutureWarning)

# Establecer el estilo de los gráficos
sns.set(style="ticks")

# Crear el gráfico hexbin
sns.jointplot(data=df, x="weekly_sales", y="fuel_price_usd_per_l", kind="hex", color="#4CB391")

# Mostrar el gráfico
plt.show()
_images/016b95ef9108dafe0cb2d1983c54b324d54b0642e166fbd149a4b67d38750db2.png

Observación

  • Este gráfico utiliza celdas hexagonales para representar la densidad de puntos en áreas donde las ventas semanales y el precio de la gasolina están más concentrados.

  • El histograma en los bordes superior y derecho muestra la variabilidad individual de cada variable (ventas semanales y precio de la gasolina, respectivamente).

Diagrama de contorno#

Los gráficos de contorno son útiles cuando los puntos de datos están densamente poblados en ciertas áreas, ya que muestran la concentración de los datos mediante líneas de contorno. En este ejercicio, crearemos un gráfico de contorno para analizar la relación entre las ventas semanales (weekly_sales) y el precio de la gasolina en USD por litro (fuel_price_usd_per_l).

  1. Importar las bibliotecas necesarias:

import seaborn as sns
import matplotlib.pyplot as plt
  1. Utilizaremos el método sns.kdeplot() para generar un gráfico de contorno con las ventas semanales y el precio de la gasolina, y rellenar las áreas con gradientes de color para reflejar la densidad de puntos.

import warnings
warnings.filterwarnings("ignore", category=FutureWarning)

# Establecer el estilo de los gráficos
sns.set_style("white")

# Crear el gráfico de contorno con densidad del núcleo (KDE)
sns.kdeplot(data=df, x="weekly_sales", y="fuel_price_usd_per_l", fill=True, cmap="Blues")

# Añadir título y etiquetas descriptivas
plt.title('Relación entre ventas semanales y precio de la gasolina')
plt.xlabel('Ventas semanales ($)')
plt.ylabel('Precio de la gasolina (USD por litro)')

# Mostrar el gráfico
plt.show()
_images/2fdd3c5b85d294be005fce57f45ed4395fd0f3556ca6365761bfc7aae2a0b135.png

Observación

  • En este gráfico, las áreas más oscuras y llenas representan zonas donde hay una mayor concentración de datos, lo que indica una relación más fuerte entre las ventas semanales y el precio de la gasolina en esas regiones.

  • Al igual que el gráfico hexbin, este gráfico de contorno permite visualizar mejor la densidad de los datos cuando hay muchas observaciones en ciertas áreas del gráfico.

Exploración de Datos con ydata-profiling#

¿Qué es ydata-profiling?#

ydata-profiling es una herramienta de Python que genera informes exploratorios automáticos y visuales a partir de un DataFrame de pandas.

Su objetivo es facilitar la exploración inicial de datos (EDA), mostrando estadísticas, valores nulos, duplicados, correlaciones y más, todo en un informe HTML.

¿Qué incluye el informe?#

  • Estadísticas descriptivas (media, mediana, desvío estándar, etc.)

  • Detección de valores faltantes y duplicados

  • Tipos de datos por variable

  • Distribuciones y gráficos por variable

  • Matriz de correlaciones

  • Alertas de calidad de datos

  • Recomendaciones para limpieza

Ventajas

  • Rápido y automático

  • Visual e interactivo

  • Exportable como HTML

  • Ideal para auditoría de datos

  • Muy útil en las primeras etapas de un análisis

  • ydata-profiling es ideal para ahorrar tiempo en la etapa de análisis exploratorio y para generar documentación de tus datos que sea clara y compartible.

import pandas as pd
from ydata_profiling import ProfileReport

filename = 'C:/GitHub/Datos/datamanip/bank/bank-full.csv'
df = pd.read_csv(filename,sep=';')

profile = ProfileReport(df,title='Informe de los datos', explorative = True)
profile.to_notebook_iframe()